Here is the LineEditor, it can work on a file or a string:
// Here is the definition of a line edit
public interface ILineEdit
{
string ApplyEdit(string input);
}
/// <summary>
/// Perform a bunch of edits on a text file or string on a line by line basis.
/// Only search and replace type edits are available.
/// </summary>
public class TextLineEditor
{
private List<ILineEdit> _pendingEdits = new List<ILineEdit>();
public TextLineEditor()
{
}
public void ApplyEditsToFile(string inputPath, string outputPath)
{
Debug.Assert(!string.IsNullOrWhiteSpace(inputPath));
Debug.Assert(!string.IsNullOrWhiteSpace(outputPath));
Debug.Assert(!outputPath.Equals(inputPath));
var inputFileInfo = new FileInfo(inputPath);
var outputFileInfo = new FileInfo(outputPath);
Debug.Assert(inputFileInfo.Exists);
Debug.Assert(!outputFileInfo.Exists);
using (TextWriter writer = new StreamWriter(outputFileInfo.FullName))
{
using (TextReader reader = new StreamReader(inputFileInfo.FullName))
{
ApplyEdits(writer, reader);
}
}
}
public string ApplyEditsToString(string text)
{
Trace.Assert(text != null);
StringBuilder sb = new StringBuilder();
using (TextWriter writer = new StringWriter(sb))
{
using (TextReader reader = new StringReader(text))
{
ApplyEdits(writer, reader);
}
}
return sb.ToString();
}
private void ApplyEdits(TextWriter writer, TextReader reader)
{
string line = null;
while ((line = reader.ReadLine()) != null)
{
foreach (ILineEdit edit in _pendingEdits)
{
line = edit.ApplyEdit(line);
}
if (line != null)
writer.WriteLine(line);
}
}
public void AddEdit(ILineEdit edit)
{
Trace.Assert(edit != null);
_pendingEdits.Add(edit);
}
}
This TextLineEditor could be replaced to work with IEnumerab<string> for line input and returning a IEnumerable<string> as an output.
Here is a LineEdit example. Note that it can do deletes by replacing with a blank string.
public class SearchAndReplace : ILineEdit
{
public enum RegExUsage
{
None = 0,
Use
}
public SearchAndReplace()
{
}
public SearchAndReplace(string searchFor, string replaceWith, bool extendedChars = false, RegExUsage regExUse = RegExUsage.None)
{
if (string.IsNullOrEmpty(searchFor))
throw new ArgumentException("Cannot be null or an empty string", "searchFor");
if (replaceWith == null)
throw new ArgumentException("Cannot be null", "replaceWith");
this.SearchFor = searchFor;
this.ReplaceWith = replaceWith;
this.ExtendedChars = extendedChars;
}
public bool IsRegEx { get; set; } = false;
public string SearchFor { get; set; } = "";
public string ReplaceWith { get; set; } = "";
public bool ExtendedChars { get; set; } = false;
public string ApplyEdit(string input)
{
if (ExtendedChars)
{
SearchFor = SearchFor.Replace("\\t","\t").Replace("\\n","\n").Replace("\\r","\r");
}
return (IsRegEx) ? SearchReplaceInString(input) : SearchReplaceInStringRegEx(input);
}
private string SearchReplaceInString(string input)
{
string output = input.Replace(SearchFor, ReplaceWith);
return output;
}
private string SearchReplaceInStringRegEx(string input)
{
string output = Regex.Replace(input, SearchFor, ReplaceWith);
return output;
}
}
Here is an example usage:
{
var inputResFilePath = ...
var outputResNewCsvFilePath ...
var outputResCsvFilePath = ...
var inputCnbFilePath = ...
var outputCnbNewCsvFilePath ...
var outputCnbCsvFilePath = ...
var replaceCommentChars = new SearchAndReplace("#", "*");
{
var replaceTabsWithGT = new SearchAndReplace("\t", " > ");
TextLineEditor resEditor = new();
resEditor.AddEdit(replaceTabsWithGT);
resEditor.AddEdit(replaceCommentChars);
resEditor.ApplyEditsToFile(inputResFilePath, outputResNewCsvFilePath);
File.Delete(outputResCsvFilePath);
File.Move(outputResNewCsvFilePath, outputResCsvFilePath);
}
{
var replaceExclamationChars = new SearchAndReplace("!", "*");
var replaceTabWithHyphen = new SearchAndReplace("\t", " - ");
TextLineEditor cnbEditor = new();
cnbEditor.AddEdit(replaceTabWithHyphen);
cnbEditor.AddEdit(replaceCommentChars);
cnbEditor.AddEdit(replaceExclamationChars);
cnbEditor.ApplyEditsToFile(inputCnbFilePath, outputCnbNewCsvFilePath);
File.Delete(outputCnbCsvFilePath);
File.Move(outputCnbNewCsvFilePath, outputCnbCsvFilePath);
}
}