Today, I thought about replacing text in streams. I noticed that .NET 4 provides methods for type
Stringto replace some text, but no methods for type
StreamI found a way by converting the stream to a string in a first step and by replacing text in a second step.
new StreamReader(i).ReadToEnd().Replace("old text", "new text")
For a lot of cases this is alright and there is nothing to worry about. But if the source is a huge amount of data and I do not want to hold it in memory all the time, things get tricky. For these cases I wrote a simple method called
ReplaceTextInStream
The method gets four arguments: an input stream, an output stream, a string with a pattern to search for and a string with the replacement value. If one argument is null, a ArgumentNullException is thrown. Here is the code: Enjoy!
public static void ReplaceTextInStream(Stream input, Stream output, string pattern, string replacement)
{
if (input == null)
{
throw new ArgumentNullException("input");
}
if (output == null)
{
throw new ArgumentNullException("output");
}
if (pattern == null)
{
throw new ArgumentNullException("pattern");
}
if (replacement == null)
{
throw new ArgumentNullException("replacement");
}
StreamReader r = new StreamReader(input);
StreamWriter w = new StreamWriter(output);
// Input and Pattern are empty => Output = Replacement
if(input.Length == 0 && pattern.Length == 0)
{
w.Write(replacement);
}
// Pattern is empty => Output = Input
if (input.Length != 0 && pattern.Length == 0)
{
while (!r.EndOfStream)
{
w.Write((char)r.Read());
}
}
// Init empty Stack
List<char> stack = new List<char>();
// Loop over input characters
while (!r.EndOfStream)
{
// Read next input character
char c = (char)r.Read();
// Compare characters
if (pattern[stack.Count] == c)
{
// Match => Put it on Stack
stack.Add(c);
// Match complete?
if (stack.Count == pattern.Length)
{
// Write Replacement and clear Stack
w.Write(replacement);
stack.Clear();
}
}
else
{
// No Macth => Stack filled?
if (stack.Count != 0)
{
// Write and Clear Stack
foreach (var tc in stack)
{
w.Write(tc);
}
stack.Clear();
}
// Copy current character
w.Write(c);
}
}
// After Loop: Stack filled?
if (stack.Count != 0)
{
// Write and Clear Stack
foreach (var tc in stack)
{
w.Write(tc);
}
stack.Clear();
}
w.Flush();
}