0

Given a Regex.Replace evaluator with four parameters, is it possible to conditionally add a leading zero to one of the parameters?

NOTE: I am using Visual Studio Ultimate 2013 (with C# version 5).

While the question may be similar to this, a critical difference is that my evaluator has multiple parameters and I need to conditionally add a leading zero to one of the four parameters.

Is there a way to either:

(a) add a conditional component to $3 in the evaluator expression, or
(b) intercept the Regex.Replace function to apply the conditional leading zero to parameter $3?

This is what "conditional" means. *Parameter $3 must hold two numbers. If $3 is between 1 and 9, a leading zero needs to be added; if greater than 9, then no zero needs to be added.

private static void Main(string[] args)
{
    const string search = "SCI.9-12.2.2.PO 1.a";
    const string pattern = @"SCI\.9-12\.(\d)\.(\d)\.PO (\d{1,2})(.\w)?";
    const string evaluator = "SCHS-S$1C$2-$3$4";

    /*
     * add leading zero to $3 only if $3 is a single-digit
     */

    var output = Regex.Replace(search, pattern, evaluator);

    Console.WriteLine(output);
}

Here is an example what what I am trying to achieve:

  • input: SCI.9-12.2.2.PO 1.a
  • output: SCHS-S2C2-01.a

or

  • input: SCI.9-12.2.2.PO 10.a
  • output: SCHS-S2C2-10.a

In addition to looking for other SO questions and answers, I looked at MSDN but did not see any example that pertained to my situation.

RandomHandle
  • 641
  • 7
  • 25
  • What do you mean by "conditional leading zero"? Do you mean an *optional* zero? Does the presence-of (or lack-of) a zero change the rest of the expression? If so, then it might be easier two have two separate regular-expressions and your validation code need only ensure at least one of them passes. – Dai Jun 21 '17 at 21:37
  • Thank you for the clarifying edits. I think you'll want to use the `MatchEvaluator` to provide custom per-capture replacement logic. – Dai Jun 21 '17 at 21:39
  • @Dai -- what I mean is that the `$4` parameter must be two-digits long; if $4 is only a single digit, it needs a leading zero. – RandomHandle Jun 21 '17 at 21:39
  • 1
    I think you mean `$3`. – NetMage Jun 21 '17 at 21:40
  • You are correct @NetMage --- It's updated. – RandomHandle Jun 21 '17 at 21:42

2 Answers2

2

Use a MatchEvaluator lambda instead of a replacement string.

var output = Regex.Replace(search, pattern, s => $"SCHS-S{s.Groups[1].Value}C{s.Groups[2].Value}-{(Regex.IsMatch(s.Groups[3].Value, @"^[1-9]$") ? ("0"+s.Groups[3].Value) : s.Groups[3].Value)}{s.Groups[4].Value}");

Or, if you're like me and think a lot of special purpose collections should be replaced with generic collections and see too much repetition above,

var output = Regex.Replace(search, pattern, s => {
    var GroupValues = s.Groups.Cast<Group>().Select(g => g.Value).ToArray();
    return $"SCHS-S{GroupValues[1]}C{GroupValues[2]}-{(Regex.IsMatch(GroupValues[3], @"^[1-9]$") ? "0" + GroupValues[3] : GroupValues[3])}{GroupValues[4]}";
});
NetMage
  • 26,163
  • 3
  • 34
  • 55
1

You could probably use a delegate.

        string sTrg = "SCI.9-12.2.2.PO 1.a";
        Console.WriteLine("{0}", sTrg);

        Regex rX = new Regex(@"SCI\.9-12\.(\d)\.(\d)\.PO[ ](\d{1,2})(.\w)?");
        Console.WriteLine("{0}", rX.Replace(sTrg, 
            delegate (Match m) {
                return "SCHS-S" + m.Groups[1] + "C" + m.Groups[2] + "-" +
                       (m.Groups[3].Length == 1 ? "0" : "") + m.Groups[3] + m.Groups[4];
            }));