I\'m in a situation where I\'d like to take a string and split it in half, respecting words so that this string here
doesn\'t get split into this str
I wanted to leave this as a comment but do not have enough rep points. The top solution right now fails pretty easily because it does not check for "-1" when using the indexOf method. See this fiddle:
http://jsfiddle.net/7RNBu/7/
var s = "This is a long strinjjjjjjjjjjjjjjjjg";
var middle = Math.floor(s.length / 2);
var before = s.lastIndexOf(' ', middle);
var after = s.indexOf(' ', middle + 1);
if (middle - before < after - middle) {
middle = before;
} else {
middle = after;
}
var s1 = s.substr(0, middle);
var s2 = s.substr(middle + 1);
This will split your string based on word count (not character count, so the exact length of each half could be quite different, depending on the placement of long & short words).
var s = "This is a string of filler text";
var pieces = s.split(" "),
firstHalfLength = Math.round(pieces.length/2),
str1 = "",
str2 = "";
for (var i = 0; i < firstHalfLength; i++){
str1 += (i!=0?" ":"") + pieces[i];
}
for (var i = firstHalfLength; i < pieces.length; i++){
str2 += (i!=firstHalfLength?" ":"") + pieces[i];
}
document.write(s);
document.write("<br />"+str1);
document.write("<br />"+str2);
// Output
This is a string of filler text
This is a string
of filler text
http://jsfiddle.net/daCrosby/7RNBu/2/
I first thought I had an off-by-one error, but I eventually worked through it. Here's a working example.
Now to break down the logic used:
var calculate = function(initialString) {
var halfwayPoint = Math.floor(initialString.length / 2);
var strArray = initialString.split(' ');
// Caluclate halfway point, then break string into words
var wordFlag; // Will be split point
var charCount = 0;
_.each( strArray, function(word, strArrayIndex) {
if (wordFlag) return false;
// If we have the location, exit
// If charCount is before the halfway point
// and the end of word is after halfway point
// Then set the flag
// We add strArrayIndex to the word length to include spaces
if (charCount <= halfwayPoint &&
((charCount + word.length + strArrayIndex) >= halfwayPoint) ) {
wordFlag = strArrayIndex;
return false;
}
// Increase charCount to be length at the end of this word
charCount += (word.length);
});
if (!wordFlag) return null;
// Split the word array by the flag we figured out earlier
var lineOneArray = strArray.slice(0, (wordFlag + 1));
var lineTwoArray = strArray.slice(wordFlag + 1);
// We now join the word arrays into a string, stripping beginning and ending spaces.
var stOne = (lineOneArray.join(' ')).replace(/^\s\s*/, '').replace(/\s\s*$/, '');
var stTwo = (lineTwoArray.join(' ')).replace(/^\s\s*/, '').replace(/\s\s*$/, '');
// Finally return the split strings as an array.
return [stOne, stTwo];
};
If anyone sees holes in my logic, let me know! I'm pretty sure this works in most cases though.
If you'd like the second string to be longer than the first, (ie have the line break before rather than after the middle word), then don't add +1 to wordFlag.
You might also care about newlines, tabs, as well as spaces, so I would use a regex like this:
var s = "this string here";
var idx = s.length / 2;
while (idx < s.length && s[idx].match(/\s/) == null)
idx++;
var s1 = s.substring(0, idx);
var s2 = s.substring(idx);
document.getElementById("s1").innerText = s1;
document.getElementById("s2").innerText = s2;
See this fiddle: http://jsfiddle.net/nS6Bj/5/
Look for the first space before and after the middle, and pick the one closest to the middle.
Example:
var s = "This is a long string";
var middle = Math.floor(s.length / 2);
var before = s.lastIndexOf(' ', middle);
var after = s.indexOf(' ', middle + 1);
if (middle - before < after - middle) {
middle = before;
} else {
middle = after;
}
var s1 = s.substr(0, middle);
var s2 = s.substr(middle + 1);
Demo: http://jsfiddle.net/7RNBu/
(This code assumes that there actually are spaces on both sides of the middle. You would also add checks for before
and after
being -1
.)
The check that I talked about in the node would be done correctly like this:
if (before == -1 || (after != -1 && middle - before >= after - middle)) {
middle = after;
} else {
middle = before;
}
Here is a fiddle where you can edit the text and see the result immediately: http://jsfiddle.net/Guffa/7RNBu/11/