String is a data type that any developer spends most of time working with. We format, we replace, we sanitize, we prettify, we trim, we encode, we decode, we serialize… Strings tirelessly, over and over
And it’s virtually impossible to think about a JavaScript framework without some kind of a “String Helper” construct.
In this article, we’re going to create a modular o2.StringHelper object.
You can click here, to get the source code of the entire StringHelper suite (8Kb zipped archive) »»
o2.StringHelper Core
First, let’s start with creating a very basic module with only a few core methods
Those methods will be the ones that we are sure we’ll be using almost always — hence the name “Core”.
//file: o2.stringhelper.core.js
if(typeof o2 == 'undefined') {
o2 = {};
}
/**
* Package: o2.stringhelper.core
* Module: o2.StringHelper
* Dependencies: none (can run standalone)
*
* A String helper.
*/
( function(o2, window, undefined) {
/**
* Module Configuration
*/
var config = {
constants: {
GUID_MULTIPLIER: 10000,
regExp: {
TRIM: /^\s+|\s+$/g,
WHITESPACE:/\s+/g
}
}
};
o2.StringHelper = {
/**
* Creates a globally unique identifier (for that browsing session);
* @return a unique GUID.
*/
createGuid: function() {
return [(new Date()).getTime(), Math.floor(config.constants.GUID_MULTIPLIER * Math.random())].join('');
},
/**
* Concatanes all its arguments into a single String.
* This is faster than adding those strings with +.
* @return the concataneted String.
*/
concat: function() {
return Array.prototype.slice.call(arguments).join('');
},
/**
* Works similar to C#'s String.Format.
*
* Usage Example:
* o2.StrinHelper.format("Hello {0}. What's going on in {1}?", 'Ninja',
* 'California');
* //will return "Hello Ninja. What's going on in California"
* @return the formated String.
*/
format: function() {
var args = arguments;
var pattern = RegExp(['{', '([1-' , (args.length-1) , '])' , '}'].join(''), 'g');
return string.replace(pattern, function(match, index) {
return args[index];
});
},
/**
* Simply removes the phrases that match the regExp from the String.
* @param {String} str - the String to process.
* @param {RegExp} regExp - the regular expression to process agains.
* @return the processed String.
*/
remove: function(str, regExp) {
return str.replace(regExp, '');
},
/**
* Trims white space from beginning and end of the String.
* @param {String} str - the String to process.
* @param {Boolean} shouldCompact - Optional (default: false)
* if true, multiple whitespace is compacted into single whitespace.
* @return the processed String.
*/
trim: function(str, shouldCompact) {
shouldCompact = shouldCompact || false;
var constants = config.constants;
var regExp = constants.regExp
return shouldCompact ? str.replace(regExp.WHITESPACE, ' '
).replace(regExp.TRIM, ''):str.replace(regExp.TRIM, '');
}
};
}(o2, this));
Note that we’ve encapsulated variables that may be prone to change in a global config variable. This is a good practice to follow, if you are developing re-usable libraries.
Secondly, even though the functions are self-explanatory, we’ve documented our code. We’ll be dealing with a method to automagically create an HTML API documentation using these JS-Doc comments, in a following tutorial. Then it will be more obvious how crucial it is to write a solid documentation for your library.
o2.StringHelper “Transform” Partial Module
Now that we have the core object, let us extend it with additional methods, by module augmentation:
//file: o2.stringhelper.transform.js
if(typeof o2 == 'undefined') {
var o2 = {};
}
if(o2.StringHelper == undefined) {
o2.StringHelper = {};
}
/**
* Package: o2.stringhelper.transform
* Module: o2.StringHelper
* Dependencies: none (can run standalone)
*
* This package is responsible for simple
* string stripping operations.
*/
( function(me, window, undefined) {
var config = {
constants: {
TRUNCATION_LENGTH: 100,
regExp: {
BR_2_NL:/<br\s*\/?>/g,
NL_2_BR:/\r\n|\n|\r/g,
REMOVE_TAGS:/<[\/]?([a-zA-Z0-9]+)[^>^<]*>/ig,
CAMEL_CASE: /(\-[a-z])/g,
ALL_CAPS: /([A-Z])/g
},
text: {
ELLIPSIS: '...',
DASH: '-',
UNDERSCORE: '_',
NEW_LINE: '\n',
BR: '<br />'
}
}
};
/**
* Replaces HTML <br /> tags with new line.
* @param {String} str - the String to format.
* @return the formatted String.
*/
me.br2nl = function(str) {
var constants = config.constants;
return str.replace(constants.regExp.BR_2_NL, constants.text.NEW_LINE);
};
/**
* Replaces new lines (\n] with HTML <br /> tags.
* @param {String} str - the String to format.
* @return the formatted String.
*/
me.nl2br = function(str) {
var constants = config.constants;
return str.replace(constants.regExp.NL_2_BR, constants.text.BR);
};
/**
* Removes all the HTML tags in the String.
* @param {String} str - the String to process.
* @return the cleaned output.
*/
me.removeTags = function(str) {
return str.replace(config.constants.regExp.REMOVE_TAGS, '');
};
/**
* Add an ellipsis (...), if the length of the String is greated than
* maxLength.
* @param {String} str - the String to process.
* @param {Integer} maxLength - Optional (defaults to
* config.constants.TRUNCATION_LENGTH),
* maksimum String length that's allowed without truncation.
* @return the processed String.
*/
me.addEllipsis = function(str, maxLength) {
var ellipsis = config.constants.text.ELLIPSIS;
var eLen = ellipsis.length;
maxLength = maxLength ? maxLength : config.constants.TRUNCATION_LENGTH;
if(str.length > maxLength) {
return [str.substr(0, maxLength-eLen), ellipsis].join('');
}
return str;
};
/**
* Converts the input to camel case.
* i.e. if input is 'lorem-ipsum', the output is 'loremIpsum'.
* This is especially useful for converting CSS classes
* to their DOM style representations.
* @param {String} input - the String to convert.
* @return the formatted String.
*/
me.toCamelCase = function(input) {
var constants = config.constants;
return input.replace(constants.regExp.CAMEL_CASE, function(match) {
return match.toUpperCase().replace(constants.text.DASH, '');
});
};
/**
* Converts a string of the form 'loremIpsum' to 'lorem-ipsum'.
* @param {String} input - the String to convert.
* @return the formatted String.
*/
me.toDashedFromCamelCase = function(input) {
var constants = config.constants;
return input.replace(constants.regExp.ALL_CAPS, function(match) {
return [constants.text.DASH, match.toLowerCase()].join('');
});
};
/**
* Converts a string of the form 'lorem-ipsum' to 'lorem_ipsum'.
* @param {String} input - the String to convert.
* @return the formatted String.
*/
me.toUnderScoreFromCamelCase = function(input) {
var constants = config.constants;
return input.replace(constants.regExp.ALL_CAPS, function(match) {
return [constants.text.UNDERSCORE, match.toLowerCase()].join('');
});
};
}(o2.StringHelper, this));
As you see, we try to create our module as much independent from other modules as possible.
For instance, instead of using o2.StringHelper.remove from o2.stringhelper.core.js file, we prefer to use str.replace(‘string’, regExp) instead, so that we don’t create a dependency to the StringHelper core file.
o2.StringHelper “Strip” Partial Module
If we design our modules without inter-dependency, then we can lazy-load and mix them in any order we like, which is a great advantage
![]()
Let’s define another independent partial module:
//file: o2.stringhelper.strip.js
if(typeof o2 == 'undefined') {
var o2 = {};
}
if(o2.StringHelper == undefined) {
o2.StringHelper = {};
}
/**
* Package: o2.stringhelper.strip
* Module: o2.StringHelper
* Dependencies: none (can run standalone)
*
* This package is responsible for simple string stripping operations.
*/
( function(me, window, undefined) {
/**
* Removes non alphanumeric characters from the String.
* @param {String} str - the String to format.
* @return the formatted String.
*/
me.stripNonAlpha = function(str) {
return str.replace(/[^A-Za-z ]+/g,'');
};
/**
* Removes alpha numeric characters from the String.
* @param {String} str - the String to format.
* @return the formatted String.
*/
me.stripNonAlphaNumeric = function(str) {
return str.replace(/[^A-Za-z0-9 ]+/g, '');
};
/**
* Removes non numeric characters from the String.
* @param {String} str - the String to format.
* @return the formatted String.
*/
me.stripNonNumeric = function(str) {
return str.replace(/[^0-9-.]/g, '');
};
/**
* Removes numeric characters from the String.
* @param {String} str - the String to format.
* @return the formatted String.
*/
me.stripNumeric = function(str) {
return str.replace(/[0-9]/g, '');
};
}(o2.StringHelper, this));
o2.StringHelper “Generate” Partial Module
This is just a draft. We may be adding more methods to this module.
//file:o2.stringhelper.generate.js
if(typeof o2 == 'undefined') {
var o2 = {};
}
if(o2.StringHelper == undefined) {
o2.StringHelper = {};
}
/**
* Package: o2.stringhelper.generate
* Module: o2.StringHelper
* Dependencies: none (can run standalone)
*
* This package is responsible for simple string generations.
*/
( function(me, window, undefined) {
/**
* Module configuration.
*/
var config = {
defaultRandomLength : 8
};
/**
* Generates a random string
* @param {Integer} length - (optional - default: config.defaultRandomLength)
* length of the String to be generated.
* @return the generated String.
*/
me.generateRandom = function(length) {
var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz';
var len = length || config.defaultRandomLength;
var charsLength = chars.length;
var randomString = '';
var randomNumber = 0;
var buffer = [];
for (var i = 0; i < len; i++) {
randomNumber = Math.floor(Math.random() * charsLength);
buffer.push(chars.substring(randomNumber, randomNumber + 1))
}
return buffer.join('');
};
}(o2.StringHelper, this));
o2.StringHelper “Encode” Partial Module
May be this module will be doing more convoluted encoding/decoding operations in the future.
Currently it’s in its draft form, waiting to be evolved as needed.
//file: o2.stringhelper.encode.js
if(typeof o2 == 'undefined') {
var o2 = {};
}
if(o2.StringHelper == undefined) {
o2.StringHelper = {};
}
/**
* Package: o2.stringhelper.core
* Module: o2.StringHelper
* Dependencies: none (can run standalone)
*
* Responsible for encoding and decoding Strings.
*/
( function(me, window, undefined) {
/**
* Encodes special charaters to their corresponding HTML entities.
* If possible try using this try using standard
* encoding methods like encodeURIComponent, instead of
* using this method.
* @param {String} str - the String to process
* @return the processed String.
*/
me.encode = function(str) {
return str
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"')
.replace(/ /g, ' ');
};
/**
* Decodes HTML entities back to normal characters.
* If possible try using this try using standard
* decoding methods like decodeURIComponent, instead of
* using this method.
* @param {String} str - the String to process
* @return the processed String.
*/
me.decode = function() {
return str
.replace(/<|</g, '<')
.replace(/>|>/g, '>')
.replace(/"|"|"t;/g, '"')
.replace(/'|'|&aposs;/g, '\'')
.replace(/ | /g, ' ')
.replace(/&|&/g, '&');
};
}(o2.StringHelper, this));
Conclusion
We’ve seen a demonstration of how to create a utility object by splitting it into smaller partial modules.
We’ve also seen that it’s important to factor out important configuration data, to give flexibility to our modules.
We could, very well, have developed a giant StringHelper static class and lump all the functionality to it, in one big file. However, chunking our module to logical sub-modules and separating each module in its own file makes them more manageable and flexible
Do you have any questions?
Can we improve this methodolody further?
I’d love to hear your comments


Tiny (sugg/qu)estion: What do you think about using the single character and semantically better … (…) instead of … (three dots)? I’m just asking about your opinion btw, as this may not be the optimal method (e.g. line-break issues, acceptance, …).
Halil, you’re right. it’s semantically better.
I’m taking a note of it, it requires testing in various browsers, though I think there won’t be too much cross-browser issues.
You see the reason I’ve encapsulated these kinds of things in config.constans
?
Anything that’s prone to change should be factored out, to avoid find&replace hassles
Thanks for your suggestion.
Yes, I appreciate your use of constants as config objects for anything configurable. And it’s nice to have functions in partial modules. It helps to include only what’s needed. (Btw, our nice WordPress seems to have taken care of those dots
)
Yes, wordpress can cause headaches when you paste source code in comments
I also strongly support partials.
in my honest opinion small, loosely coupled modules are the future, and large, tightly-bound monolithic libraries are the past!