Reputation: 7727
These strings may be long paragraphs, so I'm not sure it's best to split the entire string with a space delimiter. I'm trying to get, say, the first 10 words and wrap them in a span:
'<span class="easing">' + string + '</span>'
Then rejoin that with the second half of the original split. Suggestions on a super efficient way to do this? It would affect at most three paragraphs on the page at a time.
EDITED
Here's a kicker — The split should occur after the 9th word OR at the end of the first sentence (if that sentence is less than 9 words).
EXAMPLE
var origString = 'Coming into the world on Elvis’ birthday with a doctor named Presley seemed fortuitous until, wielding the silvery smooth scalpel in his aged unsteady hand, the doctor sliced through the walls of my mother’s uterus and into my unborn skin. Inside the warm soothing waters of my mother’s womb, inside the silent weightlessness, I was safe. Then the prick of cold steel marked the first in a series of rude awakenings. I was scarred for life even before birth.';
var newString = '<span="easing">Coming into the world on Elvis’ birthday with a doctor</span> named Presley seemed fortuitous until, wielding the silvery smooth scalpel in his aged unsteady hand, the doctor sliced through the walls of my mother’s uterus and into my unborn skin. Inside the warm soothing waters of my mother’s womb, inside the silent weightlessness, I was safe. Then the prick of cold steel marked the first in a series of rude awakenings. I was scarred for life even before birth.';
Or with a short sentence that starts the paragraph:
var origString = '“Is he okay? Tell me everything’s okay” she pleas, her desperate need to confirm my health competing with her own need for consolation.';
var newString = '<span class="easing">“Is he okay?</span> Tell me everything’s okay” she pleas, her desperate need to confirm my health competing with her own need for consolation.';
Upvotes: 4
Views: 1123
Reputation: 36075
Considering you are only going to be scanning at most about 100 chars (unless you have URIs or very long words) then scanning character by character is quite optimal. You could optimise this by using .indexOf() in certain places, but you'd loose what you gained in having to check for each different character that could terminate a sentence.
function spanomatic ( str, words ) {
var i, l, c;
for ( i=0, l=str.length; i<l; i++ ) {
c = str.charAt(i);
if ( c == ' ' ) {
if ( words-- <= 0 ) {
str = '<span>'+str.substring(0,i)+'</span>'+str.substring(i);
break;
}
}
else if ( ('?!.;:').indexOf(c) != -1 ) {
str = '<span>'+str.substring(0,i)+'</span>'+str.substring(i);
break;
}
}
return str;
}
spanomatic ( 'Pass your string here', 9 );
(The above code assumes your text will always be correctly gramatically termintated (i.e. contain at least one of ?!.;:) - if not then it would be possible for a paragraph with less than 9 words to end up spanless. This could be fixed by a few changes however...)
note for future readers
If you're going for a 'super efficient' way of doing string searching avoid Regular Expressions (unless you really need their power). The accepted answer for this question is concise and nicely put together function - don't get me wrong - but it's about 70% slower than just scanning the string with a for loop (in my tests on FireFox & Chrome at least)... and that's even when comparing after moving the Regular Expression definitions outside of Bergi's function (i.e. using pre-compiled regexps rather than recreating them every time the function is called).
http://jsperf.com/compare-regexp-vs-char-scanning
Upvotes: 2
Reputation: 34915
How about this code:
var str = 'asda adsfadsf asdfadfadsf adsfsdafadf. adfadfadfad adfadfdaf adfadfadf adfadf \afsgasfggasfg SFGDFGDSFGH dfghdsghdgas hadghdagh';
var sentences = [], words = str.split(' ');
for (var i = 0; i < 9; i++) {
if (words[i].lastIndexOf('.') !== -1) {
sentences.push(words[i]);
break;
} else {
sentences.push(words[i]);
}
}
words.slice(sentences.length, words.length);
$('<span>' + sentences.join(' ') + '</span>').appendTo($('#log'));
I have it under fiddle so you can test. You would want to do this in a loop with the remainder of arr1.
Update:
If it's not just the full stop but also ?!:;etc. then create a RegExp
and test instead of doing lastIndexOf('.')
Upvotes: 0
Reputation: 186103
Here. It's a bit code-golfy though. Sorry.
$( 'p' ).html(function ( i, text ) {
var re = /(.+?)\s/g, c = 0, res;
while ( res = re.exec( text ) ) if ( ++c === 10 || res[1].slice( -1 ) === '.' ) break;
var p = re.lastIndex;
return '<span class="easing">' + text.slice( 0, p ) + '</span>' + text.slice( p );
});
Live demo: http://jsfiddle.net/3DaEV/
Upvotes: 0
Reputation: 665545
return string.replace(/.+?[,.?!]|.+$/, function(match, index, string){
var words = match.split(/\s+/);
words[ words.length<10 ? words.length-1 : 9 ] += '</span>';
return '<span class="easing">' + words.join(" ");
});
This matches the first sentence-like thing (or the whole string - unless linebreaks), and wraps the first 10 words of it in that span. Works for both your sample inputs, but also on smaller ones. Returns the empty string for an empty string, change the regex to …|.*$
if you want an empty span.
Upvotes: 1