C# Determine Type using Regex with Switch syntactic sugar

93 views Asked by At

I have a string which based on a regex matching is of format_1 or format_2 etc. I use regex named groups to extract clientId variable.

var sampleName = "001-99-26Jul2023";
var sampleNameFormat1 = @"[0-9]{3}-(?<clientId>[0-9]{2})-[0-9]{2}[a-zA-Z]{3}[0-9]{4}";
var sampleNameFormat2 = @"[0-9]{4}-(?<clientId>[0-9]{2})-[0-9]{2}[a-zA-Z]{3}[0-9]{4}";
var sampleNameFormat3 = @"[0-9]{5}-[0-9]{2}[a-zA-Z]{3}[0-9]{4}";

var regexMatch = sampleName switch
{
    var _ when Regex.IsMatch(sampleName, sampleNameFormat1, RegexOptions.IgnoreCase) => Regex.Match(sampleName, sampleNameFormat1, RegexOptions.IgnoreCase),
    var _ when Regex.IsMatch(sampleName, sampleNameFormat2, RegexOptions.IgnoreCase) => Regex.Match(sampleName, sampleNameFormat2, RegexOptions.IgnoreCase),
    var _ when Regex.IsMatch(sampleName, sampleNameFormat3, RegexOptions.IgnoreCase) => Regex.Match(sampleName, sampleNameFormat3, RegexOptions.IgnoreCase),
    _ => null,
};


var clientIdString = regexMatch.Result("${clientId}");

if(!string.IsNullOrEmpty(clientIdString)) // If check, because `sampleNameFormat3` does not have this named grouping <clientId>
{
    int clientId = ParseInteger(clientIdString);
}

Problems:

  1. I do the regex match call twice. Is there a syntax that makes it more clean? Some way to change the switch statement? Only one Regex.Match call.
  2. As you see in Format 3 there is no <clientId>, so the last assignment
    var clientIdString = regexMatch.Result("${clientId}"); will result in clientIdString = "${clientId}".
    So, the if check will enter and error ParseInteger("${clientId}").
    The solution would be to write: var clientIdString = regexMatch.Groups["clientId"].Value; this assigns empty string and if-check does not enter. I don't know if this is the right way, so I wanted to ask you too what you consider.
1

There are 1 answers

1
Kit On BEST ANSWER

The switch is overkill, and doesn't really add much in terms of readability or succinctness.

Just do

var m = Regex.Match(sampleName, sampleNameFormat1, RegexOptions.IgnoreCase);
if (!m.Success)
    m = Regex.Match(sampleName, sampleNameFormat2, RegexOptions.IgnoreCase)
if (!m.Success)
    m = Regex.Match(sampleName, sampleNameFormat3, RegexOptions.IgnoreCase)

if (m.Success)
{
    // all your other logic
}

If you add some number of cases, then I suggest looping over the calls as you and @madreflection suggest in the comments. Something like

Match match = null;
foreach (var regexFormat in regexFormats)
{
    match = Regex.Match(sampleName, regexFormat, regexOptions.IgnoreCase);
    
    if (match.Success) break;
}

if (!match.Success) return null;

// all your other logic

or

Match match = null;
foreach (var regexFormat in regexFormats)
{
    match = Regex.Match(sampleName, regexFormat, regexOptions.IgnoreCase);
    
    if (match.Success)
    {
        // all your other logic
        return something...;
    }
}

return null;