PDA

View Full Version : C# StringBuilder Class Simulated in Javascript



VectorX
11-14-2006, 07:25 PM
Title: StringBuilder Class
Description: Simulates the C# StringBuilder Class in Javascript.
Website: www.codevendor.com
Author: Adam Smith
Email: ibulwark@hotmail.com
Date Created: November 12, 2006
Zip file includes a compressed version, speed test and fully commented sourcecode.

Attachment: 640


// Simulates the C# StringBuilder Class in Javascript.
// Parameter["stringToAdd"] - The string to add.
StringBuilder = function(stringToAdd)
{
var h = new Array();
if(stringToAdd){h[0] = stringToAdd;}
this.Append = Append;
this.AppendLine = AppendLine;
this.ToString = ToString;
this.Clear = Clear;
this.Length = Length;
this.Replace = Replace;
this.Remove = Remove;
this.Insert = Insert;
this.GetType = GetType;

// Appends the string representation of a specified object to the end of this instance.
// Parameter["stringToAppend"] - The string to append.
function Append(stringToAppend)
{
h[h.length] = stringToAppend;
}

// Appends the string representation of a specified object to the end of this instance with a carriage return and line feed.
// Parameter["stringToAppend"] - The string to append.
function AppendLine(stringToAppend)
{
h[h.length] = stringToAppend;
h[h.length] = "\r\n";
}

// Converts a StringBuilder to a String.
function ToString()
{
if(!h){ return ""; }
if(h.length<2){ return (h[0])?h[0]:""; }
var a = h.join('');
h = new Array();
h[0] = a;
return a;
}

// Clears the StringBuilder
function Clear()
{
h = new Array();
}

// Gets the StringBuilder Length
function Length()
{
if(!h){return 0;}
if(h.length<2){ return (h[0])?h[0].length:0; }
var a = h.join('');
h = new Array();
h[0] = a;
return a.length;
}

// Replaces all occurrences of a specified character or string in this instance with another specified character or string.
// Parameter["oldValue"] - The string to replace.
// Parameter["newValue"] - The string that replaces oldValue.
// Parameter["caseSensitive"] - True or false for case replace.
// Return Value - A reference to this instance with all instances of oldValue replaced by newValue.
function Replace(oldValue, newValue, caseSensitive)
{
var r = new RegExp(oldValue,(caseSensitive==true)?'g':'gi');
var b = h.join('').replace(r, newValue);
h = new Array();
h[0] = b;
return this;
}

// Removes the specified range of characters from this instance.
// Parameter["startIndex"] - The position where removal begins.
// Parameter["length"] - The number of characters to remove.
// Return Value - A reference to this instance after the excise operation has occurred.
function Remove(startIndex, length)
{
var s = h.join('');
h = new Array();

if(startIndex<1){h[0]=s.substring(length, s.length);}
if(startIndex>s.length){h[0]=s;}
else
{
h[0]=s.substring(0, startIndex);
h[1]=s.substring(startIndex+length, s.length);
}

return this;
}

// Inserts the string representation of a specified object into this instance at a specified character position.
// Parameter["index"] - The position at which to insert.
// Parameter["value"] - The string to insert.
// Return Value - A reference to this instance after the insert operation has occurred.
function Insert(index, value)
{
var s = h.join('');
h = new Array();

if(index<1){h[0]=value; h[1]=s;}
if(index>=s.length){h[0]=s; h[1]=value;}
else
{
h[0]=s.substring(0, index);
h[1]=value;
h[2]=s.substring(index, s.length);
}

return this;
}

// Gets the type
function GetType()
{
return "StringBuilder";
}
};

Twey
11-14-2006, 07:53 PM
function Append(stringToAppend)Defining functions inside the constructor is inefficient, since they must be recreated every time the constructor is called. It's a much better idea to define them as properties of the prototype.
h[h.length] = "\r\n";Javascript in browsers uses \n for linebreaks, no matter the platform. Outside browsers, it would depend on the platform.
StringBuilder = function(stringToAdd)Interesting. Usually it's the custom to use the global-creating function identifier(params) syntax for the constructor, and an inline function definition for the function properties of the object. It's certainly bad style to omit the var keyword.
function ToString()When Javascript converts to a string, it looks for the toString property. ToString will have no effect, since Javascript is case-sensitive. It's also probably a good idea to use the standard Java-like camel case convention.

Insert looks interesting, but other than that, I can't see much of a use for this.

blm126
11-15-2006, 11:17 AM
Description: Simulates the C# StringBuilder Class in Javascript.

I don't know what the StringBuilder Class is. It would be more useful if you could deescribe it

It's also probably a good idea to use the standard Java-like camel case convention.

What's Java-like came case convention?

Twey
11-15-2006, 03:20 PM
What's Java-like came case convention?First letter lower-case, first letter of each subsequent word upper-case.

mwinter
11-15-2006, 03:29 PM
Description: Simulates the C# StringBuilder Class in Javascript.

Why would anyone want to do that?

The reason why .NET and Java have StringBuilder classes is that instances of their respective String class are immutable. Any method or operator that would appear to alter the value in fact results in the creation of a completely new object, and that is inefficient. In ECMAScript, one would be working with string values, not objects.



StringBuilder = function(stringToAdd)

Why a function expression (and an undeclared variable, too), rather than a function declaration?



this.Append = Append;
this.AppendLine = AppendLine;
this.ToString = ToString;
this.Clear = Clear;
this.Length = Length;
this.Replace = Replace;
this.Remove = Remove;
this.Insert = Insert;

Now you have it backwards: using function declarations, rather than function expressions.



this.GetType = GetType;

This should be added via the prototype object; the GetType method doesn't refer to any properties of the variable object, therefore it needn't be defined with that privilege.




Defining functions inside the constructor is inefficient, since they must be recreated every time the constructor is called. It's a much better idea to define them as properties of the prototype.

In general, yes, but most of those functions utilise local data - I highlighted the one that doesn't.




I don't know what the StringBuilder Class is. It would be more useful if you could deescribe it

Internally, it contains a buffer that's used to efficiently modify a string. Taking concatenation as an example, rather than obtaining the values of two String objects, concatenating those values, then creating a new object to represent the result, the values are just added to the buffer.



What's Java-like came case convention?

A look at a Java style guide would provide more information, but essentially upper-case leading letters are reserved for class names (constructor functions, here), member names begin with a lower-case letter, and constants are all upper-case. "Words" within an identifier are capitalised, though in constants, they are separated with an underscore.

Due to the syntactic similarities between Java and ECMAScript (and its derivatives), Java coding styles tend to spill over into scripting.

Mike

Twey
11-15-2006, 04:03 PM
In general [creating functions within the constructor is inefficient], but most of those functions utilise local data - I highlighted the one that doesn't.That's not to say that they should, however. I would advocate making "h" a property of the object.

mwinter
11-15-2006, 05:26 PM
In general [creating functions within the constructor is inefficient], but most of those functions utilise local data...

That's not to say that they should, however.

No, of course. That is a value judgement, not a rule - one way or the other. The point is irrelevant here, though: don't use the code at all.

If string concatenation performance is too low for a particular script (and MSIE doesn't perform well, in some cases), then use an array and concatenate it using the Array.prototype.join method. There's no need to go as far as the code posted here.

Mike