I need code for a case-insensitive Replace
method for the StringBuilder
class. The code should work with the existing StringBuilder
. An extension method implementation would be nice.
Following is how I plan to use the method:
[TestMethod]
public void 开发者_如何转开发StringBuilder_Replace_TTD() {
StringBuilder oRequestText = new StringBuilder(File.ReadAllText("Customer.xml"));
Customer oCustomer = new Customer(null);
foreach (FieldIndex iField in Enum.GetValues(typeof(FieldIndex))) {
oRequestText.Replace("{" iField.ToString() + "}", oCustomer[iField]);
}
Debug.WriteLine(oRequestText.ToString());
}
StringBuilder
doesn't support using an IComparer
when search/replacing text (in fact, there is no search support at all). You could try rolling a character-by-character version, but that will be complicated and may still perform poorly.
Based on your use case, I would suggest using a string rather than StringBuilder
, and using string.IndexOf()
to locate the positions in the input string where you are going to do replacement - which support case insensitive search. Once you've located all of the replacement regions, create a StringBuilder
and then copy each region - replacing found text with the desired replacement values.
EDIT: Presumably you are looking to use replacement with a StringBuilder
to avoid allocating additional strings and incurring the performance hit for doing so. However, replacing text within the buffer of a StringBuilder
could actually be more expensive - particularly if the replacement strings are of different length than the source string they are replacing. Each replacement requires that characters be shifted forward or backwards depending on whether the replacing text is shorter or longer. Performing memory block moves like this will be expensive.
From: http://blogs.msdn.com/b/btine/archive/2005/03/22/400667.aspx
string Replace( string expr, string find, string repl, bool bIgnoreCase )
{
// Get input string length
int exprLen = expr.Length;
int findLen = find.Length;
// Check inputs
if( 0 == exprLen || 0 == findLen || findLen > exprLen )
return expr;
// Use the original method if the case is required
if( !bIgnoreCase )
return expr.Replace( find, repl );
StringBuilder sbRet = new StringBuilder( exprLen );
int pos = 0;
while( pos + findLen <= exprLen )
{
if( 0 == string.Compare( expr, pos, find, 0, findLen, bIgnoreCase ) )
{
// Add the replaced string
sbRet.Append( repl );
pos += findLen;
continue;
}
// Advance one character
sbRet.Append( expr, pos++, 1 );
}
// Append remaining characters
sbRet.Append( expr, pos, exprLen-pos );
// Return string
return sbRet.ToString();
}
In your example you want to do (in pseudo code):
StringBuilder oRequestText = ...;
For all fields do replace on oRequestText;
Debug.WriteLine(oRequestText.ToString());
Since you're not actually using the StringBuilder after this there is no functional difference with
StringBuilder oRequestText = ...;
string strRequest = oRequestText.ToString();
For all fields do replace on strRequest;
Debug.WriteLine(strRequest);
The normal replace functions for strings should easily support what you want to do.
I'm assuming in your real situation you do want to use the StringBuilder again. But it's probably still easiest to do a .ToString(), replace on the string, and then reload the StringBuilder with the string.
I'd use the RegEx replace method, but it means converting from a StribgBuilder to a string
oRequestText = new StringBuilder(Regex.Replace(oRequestText.ToString(), "{" iField.ToString() + "}", oCustomer[iField], RegexOptions.IgnoreCase)));
精彩评论