Click here to Skip to main content
Licence CPOL
First Posted 15 Sep 2008
Views 12,276
Downloads 21
Bookmarked 10 times

Composite Formatting with a JavaScript StringBuilder Implementation

By Mohamed Attahri | 24 Sep 2008
A very useful object when dealing with complex string concatenations

1
1 vote, 20.0%
2

3
1 vote, 20.0%
4
3 votes, 60.0%
5
4.33/5 - 5 votes
μ 4.33, σa 2.28 [?]

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.

 	//Storing the RegExp as a constant
	//to avoid initializing a new instance at each call.
	StringBuilder.prototype.CompositeFormattingRegExp = 
             new RegExp(/{\d+}|{\d+:[^\r\n{}]+}/g);


	//Appends a string using Composite Formatting 
	StringBuilder.prototype.appendFormat = function() { 
	//the first argument is the composite string 
	var Result = arguments[0]; 

	//looping through Result 
	//replacing each {n} with arguments[n+1] 
	var RegExpResult = null; 
	while ((RegExpResult = CompositeFormattingRegExp.exec(Result)) != null) { 

		//RegExp.exec doesn't return a string, 
		//type conversion is necessary 
		RegExpResult = RegExpResult.toString(); 

		//extracting the index, 
		//and the formatting string 
		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)); 
		} 

		//replacing the format item in Result string
		paramIndex++;
		var Replacement = (
                      ColonsPosition != -1) ? arguments[paramIndex].toString(paramFormat) :
                      arguments[paramIndex].toString(); 
		Result = Result.replace(RegExpResult, Replacement); 
	
		//g Flag makes RegExp remember the last position, 
		//we're updating it because directly we're modifying 
		//the string we're using the perform the search 
		CompositeFormattingRegExp.lastIndex += Replacement.length -
                      RegExpResult.length; 
	};

	//appending the formatted string to the StringBuilder 
	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.

//Overriding the Number.toString function to support custom formatting
Number.prototype.toString = function(format) { 
	switch(format) {
		case "money":
			return "$" + this;
		case "surface":
			return this + "m²";
		default:
			return this.toLocaleString();
	}
}

// create a StringBuilder
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);

// get the full string value
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.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Mohamed Attahri

Founder

France (Metropolitan) France (Metropolitan)

Member


Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board. (secure sign-in)
 
Search this forum  
 FAQ
    Noise  Layout  Per page   
  Refresh
GeneralSimilar Article - "CustomFormat" - has conditional formatting that might improve localization PinmemberScott Rippey9:00 22 Oct '09  
I wrote an article about Custom Formatting in .NET, and I think some of the techniques I used are pretty similar to yours.
I've considered creating a JavaScript version of the CustomFormat function, because it really makes it easy to create "natural language" strings, and allows custom formatting to be done on any type.
If you want to take a look, the article is here: Custom Formatting in .NET - Enhancing String.Format to all new levels![^]
Among the many features, my favorite is Conditional Formatting, which allows easy localization and allows formatting rules to be right in the string template. It's best described with an example.
result = CustomFormat("There {0:is|are} {0} {0:item|items} remaining...", items.Count)
I think some of my techniques and syntax could be way easier to implement in a JavaScript version because of the ease of (or lack of) "reflection" and evaluating string expressions.
GeneralRe: Similar Article - "CustomFormat" - has conditional formatting that might improve localization PinmemberMohamed Attahri8:20 26 Oct '09  
Questionwhat's the escape character of { or } ? Pinmemberanhchanghaudau20:13 18 Sep '08  
AnswerRe: what's the escape character of { or } ? [modified] PinmemberMohamed Attahri0:03 19 Sep '08  

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Mobile
Web01 | 2.5.120210.1 | Last Updated 24 Sep 2008
Article Copyright 2008 by Mohamed Attahri
Everything else Copyright © CodeProject, 1999-2012
Terms of Use
Layout: fixed | fluid