0

I'm trying to find a cleaner way of performing multiple sequential replacements on a single string where each replacement has a unique pattern and string replacement.

For example, if I have 3 pairs of patterns-substitutions strings:

1. /(?<!\\)\\n/, "\n"

2. /(\\)(?=[\;\:\,])/, ""

3. /(\\{2})/, "\\"

I want to apply regex replacement 1 on the original string, then apply 2 on the output of 1, and so on and so forth.

The following console program example does exactly what I want, but it has a lot of repetition, I am looking for a cleaner way to do the same thing.

SanitizeString

static public string SanitizeString(string param)
{
    string retval = param;
    //first replacement
    Regex SanitizePattern = new Regex(@"([\\\;\:\,])");
    retval = SanitizePattern.Replace(retval, @"\$1");

    //second replacement
    SanitizePattern = new Regex(@"\r\n?|\n");
    retval = SanitizePattern.Replace(retval, @"\n");

    return retval;
}

ParseCommands

static public string ParseCommands(string param)
{
    string retval = param;
    //first replacement
    Regex SanitizePattern = new Regex(@"(?<!\\)\\n");
    retval = SanitizePattern.Replace(retval, System.Environment.NewLine);

    //second replacement
    SanitizePattern = new Regex(@"(\\)(?=[\;\:\,])");
    retval = SanitizePattern.Replace(retval, "");

    //third replacement
    SanitizePattern = new Regex(@"(\\{2})");
    retval = SanitizePattern.Replace(retval, @"\");

    return retval;
}

Main

using System;
using System.IO;
using System.Text.RegularExpressions;

...

static void Main(string[] args)
{
    //read text that contains user input
    string sampleText = File.ReadAllText(@"c:\sample.txt");

    //sanitize input with certain rules
    sampleText = SanitizeString(sampleText);
    File.WriteAllText(@"c:\sanitized.txt", sampleText);

    //parses escaped characters back into the original text
    sampleText = ParseCommands(sampleText);
    File.WriteAllText(@"c:\parsed_back.txt", sampleText);
}

Don't mind the file operations. I just used that as a quick way to visualize the actual output. In my program I'm going to use something different.

David
  • 61
  • 6
  • Why not put them all in a List (or two) and run the replacements using a loop? – Caius Jard Oct 20 '19 at 06:22
  • @CaiusJard because a list would only store the Regex instance and not the string for replacement. I was thinking more about using a dictionary, but then I found out about the MatchEvaluator. Just skimming over some examples in other questions it kinda does what I'm looking for. However, I'm unable to make sense of it because all examples I saw are different. Some iterate through patterns, others use a lambda or function pointer to define the behavior of the replacement but not the pattern. I've been trying to put those together without success so far. – David Oct 20 '19 at 06:49
  • 2
    If you have to run regex replacements on the output of the previous regex replacement you just need to chain these replacements, no match evaluator will hell here. – Wiktor Stribiżew Oct 20 '19 at 07:50

1 Answers1

1

Here's one way:

var replacements = new List<(Regex regex, string replacement)>()
{
    (new Regex(@"(?<!\\)\\n"), System.Environment.NewLine),
    (new Regex(@"(\\)(?=[\;\:\,])"), ""),
    (new Regex(@"(\\{2})"), @"\"),
};

(Ideally cache that in a static readonly field):

Then:

string retval = param;
foreach (var (regex, replacement) in replacements)
{
    retval = regex.Replace(retval, replacement);
}

Or you could go down the linq route:

string retval = replacements
    .Aggregate(param, (str, x) => x.regex.Replace(str, x.replacement));
canton7
  • 37,633
  • 3
  • 64
  • 77
  • It works like a charm, and your example taught me what tuples are. Thank you! Also, for reference I had to run `Install-Package "System.ValueTuple"` on the Package Manager because VS 2017 doesn't install the package needed for these tuples automatically. There more info [here](https://stackoverflow.com/questions/38382971/predefined-type-system-valuetuple%C2%B42%C2%B4-is-not-defined-or-imported). – David Oct 21 '19 at 06:20