优化正则表达式以读取日期

Optimize regex to read date

我开发了一个在 .NET WebAPI 中使用的正则表达式,它从已格式化为最终格式的给定输入获取日期和控制代码。

我尝试使用正则表达式来避免使用多个字符串拆分。

我一直在使用 Regex101 来测试我的表达式,我有一个已经按预期工作了,但我认为它对于它的功能来说太大了。

表达式:

^([0-9]{2})+([0-9]{2})+([0-9]{2})[0-9](M|F)([0-9]{2})+([0-9]{2})+([0-9]{2})

// 获取年、月、日、代码(M|F)、年、月、日

输入:

7603259M2209058PRT<<<<<<<<<<<8

你有什么简化的建议吗?

您的正则表达式存在一个问题:您使用 + 量词量化了两位数的匹配捕获组,使它们匹配了一次或多次。 ([0-9]{2})+ 匹配任意两个 ASCII 数字的一个或多个序列,同时将最后捕获的值保留在相应的组中。参见 Repeating a Capturing Group vs. Capturing a Repeated Group

您需要从模式中删除所有 + 个字符,然后您还可以使用以下内容:

  • 使用\d匹配任何数字,同时将RegexOptions.ECMAScript选项传递给正则表达式编译方法,使其只能匹配ASCII数字(否则,\d将等于\p{Nd} 并将匹配任何 Unicode 数字,请参阅 \d less efficient than [0-9])
  • 不要使用单个字符 ((M|F)),而是使用字符 class、([MF]),这样效率更高(参见 Why is a character class faster than alternation?)。

您可以使用

var pattern = new Regex(@"^(\d{2})(\d{2})(\d{2})\d([MF])(\d{2})(\d{2})(\d{2})", RegexOptions.ECMAScript);

参见.NET regex demo

如果您想使用更短的正则表达式,您可以使用:

var pattern = new Regex(@"^(?:(\d{2})){3}\d([MF])(?:(\d{2})){3}", RegexOptions.ECMAScript);
var match = pattern.Match("7603259M2209058PRT<<<<<<<<<<<8");
if (match.Success)
{
    Console.WriteLine(match.Groups[1].Captures[0].Value); // => 76
    Console.WriteLine(match.Groups[1].Captures[1].Value); // => 03
    Console.WriteLine(match.Groups[1].Captures[2].Value); // => 25
    Console.WriteLine(match.Groups[2].Value);             // => M
    Console.WriteLine(match.Groups[3].Captures[0].Value); // => 22
    Console.WriteLine(match.Groups[3].Captures[1].Value); // => 09
    Console.WriteLine(match.Groups[3].Captures[2].Value); // => 05
}

参见C# demo and this regex demo

请注意,这是可能的,因为 .NET Regex 允许访问组堆栈内的所有捕获。