// Underscore.string // (c) 2010 Esa-Matti Suuronen // Underscore.strings is freely distributable under the terms of the MIT license. // Documentation: https://github.com/edtsech/underscore.string // Some code is borrowed from MooTools and Alexandru Marasteanu. // Version 1.1.4 (function(){ // ------------------------- Baseline setup --------------------------------- // Establish the root object, "window" in the browser, or "global" on the server. var root = this; var nativeTrim = String.prototype.trim; var parseNumber = function(source) { return source * 1 || 0; }; function str_repeat(i, m) { for (var o = []; m > 0; o[--m] = i); return o.join(''); } function defaultToWhiteSpace(characters){ if (characters) { return _s.escapeRegExp(characters); } return '\\s'; } var _s = { isBlank: function(str){ return !!str.match(/^\s*$/); }, capitalize : function(str) { return str.charAt(0).toUpperCase() + str.substring(1).toLowerCase(); }, chop: function(str, step){ step = step || str.length; var arr = []; for (var i = 0; i < str.length;) { arr.push(str.slice(i,i + step)); i = i + step; } return arr; }, clean: function(str){ return _s.strip(str.replace(/\s+/g, ' ')); }, count: function(str, substr){ var count = 0, index; for (var i=0; i < str.length;) { index = str.indexOf(substr, i); index >= 0 && count++; i = i + (index >= 0 ? index : 0) + substr.length; } return count; }, chars: function(str) { return str.split(''); }, escapeHTML: function(str) { return String(str||'').replace(/&/g,'&').replace(//g,'>') .replace(/"/g, '"').replace(/'/g, "'"); }, unescapeHTML: function(str) { return String(str||'').replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>') .replace(/"/g, '"').replace(/'/g, "'"); }, escapeRegExp: function(str){ // From MooTools core 1.2.4 return String(str||'').replace(/([-.*+?^${}()|[\]\/\\])/g, '\\$1'); }, insert: function(str, i, substr){ var arr = str.split(''); arr.splice(i, 0, substr); return arr.join(''); }, includes: function(str, needle){ return str.indexOf(needle) !== -1; }, join: function(sep) { // TODO: Could this be faster by converting // arguments to Array and using array.join(sep)? sep = String(sep); var str = ""; for (var i=1; i < arguments.length; i += 1) { str += String(arguments[i]); if ( i !== arguments.length-1 ) { str += sep; } } return str; }, lines: function(str) { return str.split("\n"); }, // reverse: function(str){ // return Array.prototype.reverse.apply(str.split('')).join(''); // }, splice: function(str, i, howmany, substr){ var arr = str.split(''); arr.splice(i, howmany, substr); return arr.join(''); }, startsWith: function(str, starts){ return str.length >= starts.length && str.substring(0, starts.length) === starts; }, endsWith: function(str, ends){ return str.length >= ends.length && str.substring(str.length - ends.length) === ends; }, succ: function(str){ var arr = str.split(''); arr.splice(str.length-1, 1, String.fromCharCode(str.charCodeAt(str.length-1) + 1)); return arr.join(''); }, titleize: function(str){ var arr = str.split(' '), word; for (var i=0; i < arr.length; i++) { word = arr[i].split(''); if(typeof word[0] !== 'undefined') word[0] = word[0].toUpperCase(); i+1 === arr.length ? arr[i] = word.join('') : arr[i] = word.join('') + ' '; } return arr.join(''); }, camelize: function(str){ return _s.trim(str).replace(/(\-|_|\s)+(.)?/g, function(match, separator, chr) { return chr ? chr.toUpperCase() : ''; }); }, underscored: function(str){ return _s.trim(str).replace(/([a-z\d])([A-Z]+)/g, '$1_$2').replace(/\-|\s+/g, '_').toLowerCase(); }, dasherize: function(str){ return _s.trim(str).replace(/([a-z\d])([A-Z]+)/g, '$1-$2').replace(/^([A-Z]+)/, '-$1').replace(/\_|\s+/g, '-').toLowerCase(); }, trim: function(str, characters){ if (!characters && nativeTrim) { return nativeTrim.call(str); } characters = defaultToWhiteSpace(characters); return str.replace(new RegExp('\^[' + characters + ']+|[' + characters + ']+$', 'g'), ''); }, ltrim: function(str, characters){ characters = defaultToWhiteSpace(characters); return str.replace(new RegExp('\^[' + characters + ']+', 'g'), ''); }, rtrim: function(str, characters){ characters = defaultToWhiteSpace(characters); return str.replace(new RegExp('[' + characters + ']+$', 'g'), ''); }, truncate: function(str, length, truncateStr){ truncateStr = truncateStr || '...'; return str.slice(0,length) + truncateStr; }, words: function(str, delimiter) { delimiter = delimiter || " "; return str.split(delimiter); }, pad: function(str, length, padStr, type) { var padding = ''; var padlen = 0; if (!padStr) { padStr = ' '; } else if (padStr.length > 1) { padStr = padStr[0]; } switch(type) { case "right": padlen = (length - str.length); padding = str_repeat(padStr, padlen); str = str+padding; break; case "both": padlen = (length - str.length); padding = { 'left' : str_repeat(padStr, Math.ceil(padlen/2)), 'right': str_repeat(padStr, Math.floor(padlen/2)) }; str = padding.left+str+padding.right; break; default: // "left" padlen = (length - str.length); padding = str_repeat(padStr, padlen);; str = padding+str; } return str; }, lpad: function(str, length, padStr) { return _s.pad(str, length, padStr); }, rpad: function(str, length, padStr) { return _s.pad(str, length, padStr, 'right'); }, lrpad: function(str, length, padStr) { return _s.pad(str, length, padStr, 'both'); }, /** * Credits for this function goes to * http://www.diveintojavascript.com/projects/sprintf-for-javascript * * Copyright (c) Alexandru Marasteanu * All rights reserved. * */ sprintf: function(){ var i = 0, a, f = arguments[i++], o = [], m, p, c, x, s = ''; while (f) { if (m = /^[^\x25]+/.exec(f)) { o.push(m[0]); } else if (m = /^\x25{2}/.exec(f)) { o.push('%'); } else if (m = /^\x25(?:(\d+)\$)?(\+)?(0|'[^$])?(-)?(\d+)?(?:\.(\d+))?([b-fosuxX])/.exec(f)) { if (((a = arguments[m[1] || i++]) == null) || (a == undefined)) { throw('Too few arguments.'); } if (/[^s]/.test(m[7]) && (typeof(a) != 'number')) { throw('Expecting number but found ' + typeof(a)); } switch (m[7]) { case 'b': a = a.toString(2); break; case 'c': a = String.fromCharCode(a); break; case 'd': a = parseInt(a); break; case 'e': a = m[6] ? a.toExponential(m[6]) : a.toExponential(); break; case 'f': a = m[6] ? parseFloat(a).toFixed(m[6]) : parseFloat(a); break; case 'o': a = a.toString(8); break; case 's': a = ((a = String(a)) && m[6] ? a.substring(0, m[6]) : a); break; case 'u': a = Math.abs(a); break; case 'x': a = a.toString(16); break; case 'X': a = a.toString(16).toUpperCase(); break; } a = (/[def]/.test(m[7]) && m[2] && a >= 0 ? '+'+ a : a); c = m[3] ? m[3] == '0' ? '0' : m[3].charAt(1) : ' '; x = m[5] - String(a).length - s.length; p = m[5] ? str_repeat(c, x) : ''; o.push(s + (m[4] ? a + p : p + a)); } else { throw('Huh ?!'); } f = f.substring(m[0].length); } return o.join(''); }, toNumber: function(str, decimals) { return parseNumber(parseNumber(str).toFixed(parseNumber(decimals))); }, strRight: function(sourceStr, sep){ var pos = (!sep) ? -1 : sourceStr.indexOf(sep); return (pos != -1) ? sourceStr.slice(pos+sep.length, sourceStr.length) : sourceStr; }, strRightBack: function(sourceStr, sep){ var pos = (!sep) ? -1 : sourceStr.lastIndexOf(sep); return (pos != -1) ? sourceStr.slice(pos+sep.length, sourceStr.length) : sourceStr; }, strLeft: function(sourceStr, sep){ var pos = (!sep) ? -1 : sourceStr.indexOf(sep); return (pos != -1) ? sourceStr.slice(0, pos) : sourceStr; }, strLeftBack: function(sourceStr, sep){ var pos = sourceStr.lastIndexOf(sep); return (pos != -1) ? sourceStr.slice(0, pos) : sourceStr; } }; // Aliases _s.strip = _s.trim; _s.lstrip = _s.ltrim; _s.rstrip = _s.rtrim; _s.center = _s.lrpad; _s.ljust = _s.lpad; _s.rjust = _s.rpad; // CommonJS module is defined if (typeof window === 'undefined' && typeof module !== 'undefined') { // Export module module.exports = _s; // Integrate with Underscore.js } else if (typeof root._ !== 'undefined') { root._.mixin(_s); // Or define it } else { root._ = _s; } }());