【问题标题】:Optimize regex to read date优化正则表达式以读取日期
【发布时间】:2022-01-07 16:09:13
【问题描述】:

我开发了一个用于 .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

你有什么简化的建议吗?

【问题讨论】:

  • 1) + 在你的模式中是错误的,将它们全部删除,2) 使用 \d 匹配一个数字,并传递 RegexOptions.ECMAScript 选项,3) 不要使用单chars,使用字符类。 new Regex(@"^(\d{2})(\d{2})(\d{2})\d([MF])(\d{2})(\d{2})(\d{2})", RegexOptions.ECMAScript)
  • 2209058 如何描述“年、月、日”?年 = 22,月 = 09,日 = 058???
  • @MathiasR.Jessen year=22, Month=09, Day=05 这就是为什么我希望在 Code(M|F) 之前多一位数字
  • @WiktorStribiżew 感谢您的建议,我保留了 [0-9] 因为它相当于 \d ,我真的不知道引擎是否将 \d 转换为 [0-9] 或如何它炒锅。我只是希望少一些陈述。
  • 在这种情况下@WiktorStribiżew 是正确的,您不需要所有那些开放式量词。 ^([0-9]{2})([0-9]{2})([0-9]{2})[0-9][MF]([0-9]{2})([0-9]{2})([0-9]{2}) 应该这样做

标签: c# regex regex-group regex-greedy


【解决方案1】:

您的正则表达式存在一个问题:您使用+ 量词量化了两位匹配的捕获组,使它们匹配一次或多次。 ([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)),而是使用字符类 ([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# demothis regex demo

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

【讨论】:

  • 感谢您的回答,我采纳了您的建议。我想找到一种方法使 Regex 表达式更小,而不是重复该模式来创建组 "(\d{2})" 6 次
  • @JoãoMendes 我添加了另一个具有重复捕获组的解决方案,但请注意它不太便携,而且不太直观。正则表达式世界中的较短并不总是意味着更好。
  • 这正是我要找的,我有类似的东西,但在 Regex101 中它没有显示为捕获的值,所以我认为它不起作用。我会保持建议小心,它并不适用于任何地方,但就我而言,我认为这是最合适的。非常感谢!
  • @JoãoMendes 确保您在兼容在线正则表达式测试仪上测试您的模式。 Regex101 不支持 .NET 正则表达式风格。
猜你喜欢
  • 1970-01-01
  • 2012-01-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多