Introduction
If you're a .NET developer, you must know how useful the StringBuilder class can be. I found this excellent article named JavaScript String Builderby K. Collins, and while the performance issues related to string concatenations were solved, I found myself missing a very neat feature of the .NET Framework: Composite Formatting.
Understanding Composite Formatting
Composite formatting allows you to separate the "static" string elements from the "variable" ones, marking it much more readable, specifically when dealing with complex and long string concatenations.
Basically, composite formatting requires two arguments:
- A
string where the variables are replaced by an integer between semicolons (or format item), representing an index in an array
- An array of objects
The composite formatting function will replace the format item {n} by the string representation of the nth element in the provided array.
A string representation is obtained by calling the toString function (built-in every object in JavaScript).
It’s very common to pass an argument to it to customize the output. You can specify this argument by adding it right after the integer in the format item, preceded by colon. It should look like this : {n:format}.
The JavaScript Implementation
Instead of implementing a function with two parameters, I thought about using the arguments property of the JavaScript function to avoid having to explicitly pass the array of values as an Array object.
In JavaScript, the arguments property is available inside functions and contains all the arguments passed to the function being executed.
In our case:
arguments[0] will be the composite string
arguments[1] will be the value used to replace "{0}" in the composite string
arguments[2] will be the value used to replace "{1}" in the composite string
- ...
arguments[n] will be the value used to replace "{n-1}" in the composite string
I'm directly extending K. Collins' StringBuilder, but the code can easily be used to extend any other object with composite formatting. I'm assuming you're familiar with RegExp and Regular Expressions.
StringBuilder.prototype.CompositeFormattingRegExp =
new RegExp(/{\d+}|{\d+:[^\r\n{}]+}/g);
StringBuilder.prototype.appendFormat = function() {
var Result = arguments[0];
var RegExpResult = null;
while ((RegExpResult = CompositeFormattingRegExp.exec(Result)) != null) {
RegExpResult = RegExpResult.toString();
var ColonsPosition = RegExpResult.indexOf(":");
var paramIndex = -1;
var paramFormat = '';
if (ColonsPosition != -1) {
paramIndex = new Number(RegExpResult.substr(
1, ColonsPosition - 1));
paramFormat = RegExpResult.substr(ColonsPosition + 1,
RegExpResult.length - 2 - ColonsPosition);
}
else {
paramIndex = new Number(RegExpResult.substr(1,
RegExpResult.length - 2));
}
paramIndex++;
var Replacement = (
ColonsPosition != -1) ? arguments[paramIndex].toString(paramFormat) :
arguments[paramIndex].toString();
Result = Result.replace(RegExpResult, Replacement);
CompositeFormattingRegExp.lastIndex += Replacement.length -
RegExpResult.length;
};
this.append(Result);
};
Example of Use
The source zip file above contains a ready-to-use StringBuilder class (a compressed version is included for production use). The following methods are what you need to know to start using it :
StringBuilder(string) (Constructor): initializes a new instance of the StringBuilder class and appends a string if passed.
append(string): appends a string, and returns the StringBuilder instance.
appendLine(string): appends a string in a new line and returns the StringBuilder instance.
appendFormat(string, arg1, arg2, ...): appends a string using Composite Formatting and returns the StringBuilder instance.
length(): returns the length of the string contained in the StringBuilder instance.
clear(): reinitializes the StringBuilder instance before returning it.
toString(separator): Returns the string contained in the StringBuilder by joining the appended strings using an optional separator.
Please note that methods related to appending strings are built using the chainability principle (jQuery-like), meaning : Every method within StringBuilder returns the object itself, allowing you to 'chain' upon it.
Number.prototype.toString = function(format) {
switch(format) {
case "money":
return "$" + this;
case "surface":
return this + "m²";
default:
return this.toLocaleString();
}
}
var sb = new StringBuilder("Initializing a new instance")
.appendLine("append text in a new line")
.appendLine("")
.appendFormat("appending text using composite formatting : {0:money}, {1:surface}, {2},
{{3}}", 100, 200, 300, 400);
var s = sb.toString();
Versions
- 15th September, 2008: Initial post.
- 19th September, 2008: Added string formatting option.
- 20th September, 2008: Bugs corrected and source code added.