Skip to content

Instantly share code, notes, and snippets.

@yurynix
Last active September 1, 2016 10:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save yurynix/2496a18daebc872769b1a91baf787c84 to your computer and use it in GitHub Desktop.
Save yurynix/2496a18daebc872769b1a91baf787c84 to your computer and use it in GitHub Desktop.
////////////
///
/// Delphin with RegExp x 131,568 ops/sec ±1.01% (85 runs sampled)
/// Delphin with for loop x 15,235 ops/sec ±0.72% (90 runs sampled)
/// Delphin with regex replace x 291,946 ops/sec ±1.08% (88 runs sampled)
/// Calypso x 323,048 ops/sec ±1.51% (87 runs sampled)
/// Fastest is Calypso
///
////////////
var trim = require( 'lodash/trim' );
var Benchmark = require('benchmark');
var suite = new Benchmark.Suite;
const wordsRegex = new RegExp( '\\S+', 'g' );
function preventWidowDelphin1( text, wordsToKeep = 2 ) {
if ( typeof text !== 'string' ) {
return text;
}
const matches = [];
let match;
while ( match = wordsRegex.exec( text ) ) {
matches.push( match );
}
if ( matches.length < 1 ) {
return text;
}
const startIndex = matches[ 0 ].index;
const endIndex = matches[ matches.length -1 ].index + matches[ matches.length - 1 ][ 0 ].length - 1;
const words = matches.map( match => match[ 0 ] );
let result;
if ( words.length <= wordsToKeep ) {
result = words.join( '\xA0' );
} else {
const endWords = words.splice( -wordsToKeep, wordsToKeep );
result = words.join( ' ' ) + ' ' + endWords.join( '\xA0' );
}
if ( startIndex === 0 && endIndex === text.length - 1 ) {
return result;
}
return text.substring( 0, startIndex ) + result + text.substring( endIndex, text.legth );
}
function preventWidowDelphin2( text, wordsToKeep = 2 ) {
if ( typeof text !== 'string' ) {
return text;
}
const SPACES = {
'\xA0': true,
' ': true,
'\n': true,
'\r': true,
'\t': true
};
let wordsCount = 0;
let inWord = false;
const newStringCharArray = new Array( text.length );
for ( let i = text.length - 1; i >= 0; i-- ) {
if ( ! SPACES[ text[ i ] ] && ! inWord ) {
inWord = true;
wordsCount++;
}
if ( SPACES[ text[ i ] ] && inWord ) {
inWord = false;
}
if ( SPACES[ text[ i ] ] && wordsCount > 0 && ( text[ i ] === '\xA0' || text[ i ] === ' ' ) ) {
if ( wordsToKeep > wordsCount ) {
newStringCharArray.push( '\xA0' );
} else {
// we change to regular space for the case when wordsToKeep is
// smaller than in a previous call to preventWidows
newStringCharArray.push( text[ i ] === '\xA0' ? ' ' : text[ i ] );
}
} else {
newStringCharArray.push( text[ i ] );
}
}
if ( wordsCount === 1 ) {
// special case, we shouldn't change anything
return text;
}
return newStringCharArray.reverse().join( '' );
};
function preventWidowDelphin3( text, wordsToKeep = 2 ) {
if ( typeof text !== 'string' ) {
return text;
}
let match;
let matches = [];
while ( ( match = wordsRegex.exec( text ) ) !== null ) {
matches.push( match );
}
if ( matches.length < 1 ) {
return text;
}
let startIndex,
endIndex = matches[ matches.length - 1 ] .index + matches[ matches.length - 1 ][ 0 ].length - 1;
if ( matches.length < wordsToKeep ) {
startIndex = matches[ 0 ].index;
} else {
startIndex = matches[ matches.length - wordsToKeep ].index;
}
return text.replace( /\s+/g, ( replaceMatch, offset ) => {
if ( offset > startIndex && offset < endIndex ) {
return '\xA0';
} else if ( replaceMatch === '\xA0' ) {
return ' ';
}
return replaceMatch;
} );
}
function preventWidowCalypso( text, wordsToKeep = 2 ) {
let words, endWords;
if ( typeof text !== 'string' ) {
return text;
}
text = text && trim( text );
if ( ! text ) {
return text;
}
words = text.match( /\S+/g );
if ( ! words || 1 === words.length ) {
return text;
}
if ( words.length <= wordsToKeep ) {
return words.join( '\xA0' );
}
endWords = words.splice( -wordsToKeep, wordsToKeep );
return words.join( ' ' ) + ' ' + endWords.join( '\xA0' );
}
// add tests
suite.add( 'Delphin with RegExp', function () {
preventWidowDelphin1( 'Millions of short, easy to remember domains will be available when the .blog domain goes live November 21.', 2 );
})
.add('Delphin with for loop', function () {
preventWidowDelphin2( 'Millions of short, easy to remember domains will be available when the .blog domain goes live November 21.', 2 );
})
.add('Delphin with regex replace', function () {
preventWidowDelphin3( 'Millions of short, easy to remember domains will be available when the .blog domain goes live November 21.', 2 );
})
.add('Calypso', function () {
preventWidowCalypso( 'Millions of short, easy to remember domains will be available when the .blog domain goes live November 21.', 2 );
})
// add listeners
.on('cycle', function( event ) {
console.log(String(event.target));
} )
.on('complete', function() {
console.log('Fastest is ' + this.filter( 'fastest' ).map( 'name' ) );
})
// run async
.run( { 'async': true } );
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment