string str1 = \"12345ABC...\\\\...ABC100000\";
// Hypothetically huge string of 100000 + Unicode Chars
str1 = str1.Replace(\"1\", string.Empty);
str1 = str1.Rep
1. What is the fastest way of replacing these values, ignoring memory concerns?
The fastest way is to build a custom component that's specific to your use case. As of .NET 4.6, There's no class in the BCL designed for multiple string replacements.
If you NEED something fast out of the BCL, StringBuilder is the fastest BCL component for simple string replacement. The source code can be found here: It's pretty efficient for replacing a single string. Only use Regex if you really need the pattern-matching power of regular expressions. It's slower and a little more cumbersome, even when compiled.
2. What is the most memory efficient way of achieving the same result?
The most memory-efficient way is to perform a filtered stream copy from the source to the destination (explained below). Memory consumption will be limited to your buffer, however this will be more CPU intensive; as a rule of thumb, you're going to trade CPU performance for memory consumption.
Technical Details
String replacements are tricky. Even when performing a string replacement in a mutable memory space (such as with StringBuilder), it's expensive. If the replacement string is a different length than original string, you're going to be relocating every character following the replacement string to keep the whole string contiguous. This results in a LOT of memory writes, and even in the case of StringBuilder, causes you to rewrite most of the string in-memory on every call to Replace.
So what is the fastest way to do string replacements? Write the new string using a single-pass: Don't let your code go back and have to re-write anything. Writes are more expensive than reads. You're going to have to code this yourself for best results.
High-Memory Solution
The class I've written generates strings based on templates. I place tokens ($ReplaceMe$) in a template which marks places where I want to insert a string later. I use it in cases where XmlWriter is too onerous for XML that's largely static and repetitive, and I need to produce large XML (or JSON) data streams.
The class works by slicing the template up into parts and places each part into a numbered dictionary. Parameters are also enumerated. The order in which the parts and parameters are inserted into a new string are placed into an integer array. When a new string is generated, the parts and parameters are picked from the dictionary and used to create a new string.
It's neither fully-optimized nor is it bulletproof, but it works great for generating very large data streams from templates.
Low-Memory Solution
You'll need to read small chunks from the source string into a buffer, search the buffer using an optimized search algorithm, and then write the new string to the destination stream / string. There are a lot of potential caveats here, but it would be memory efficient and a better solution for source data that's dynamic and can't be cached, such as whole-page translations or source data that's too large to reasonably cache. I don't have a sample solution for this handy.
Sample Code
Desired Results
Template
Test Case
class Program
{
static string[,] _users =
{
{ "25", "Administrator" },
{ "29", "Robert" },
{ "55", "Amanda" },
};
static StringTemplate _documentTemplate = new StringTemplate(@"$Rows$ ");
static StringTemplate _rowTemplate = new StringTemplate(@"
");
static void Main(string[] args)
{
_documentTemplate.SetParameter("TableName", "Users");
_documentTemplate.SetParameter("Rows", GenerateRows);
Console.WriteLine(_documentTemplate.GenerateString(4096));
Console.ReadLine();
}
private static void GenerateRows(StreamWriter writer)
{
for (int i = 0; i <= _users.GetUpperBound(0); i++)
_rowTemplate.GenerateString(writer, _users[i, 0], _users[i, 1]);
}
}
StringTemplate Source
public class StringTemplate
{
private string _template;
private string[] _parts;
private int[] _tokens;
private string[] _parameters;
private Dictionary _parameterIndices;
private string[] _replaceGraph;
private Action[] _callbackGraph;
private bool[] _graphTypeIsReplace;
public string[] Parameters
{
get { return _parameters; }
}
public StringTemplate(string template)
{
_template = template;
Prepare();
}
public void SetParameter(string name, string replacement)
{
int index = _parameterIndices[name] + _parts.Length;
_replaceGraph[index] = replacement;
_graphTypeIsReplace[index] = true;
}
public void SetParameter(string name, Action callback)
{
int index = _parameterIndices[name] + _parts.Length;
_callbackGraph[index] = callback;
_graphTypeIsReplace[index] = false;
}
private static Regex _parser = new Regex(@"\$(\w{1,64})\$", RegexOptions.Compiled);
private void Prepare()
{
_parameterIndices = new Dictionary(64);
List parts = new List(64);
List