用于排除重叠匹配的正则表达式

时间:2016-05-03 15:58:30

标签: .net regex

我试图在.NET中编写一个与客户/事项编号匹配的正则表达式。客户编号或事项编号由一系列字母或数字组成,客户/事项编号是客户编号和由/-或{{分隔的事项编号的组合1}}。例如.

在以下字符串中:

  

Foo [1234/101] bar 456B / 102 baz

我希望它在0204A/101[1234-101]上匹配。我已经提出了这种模式:

456B/102

我可以使用捕获组从每次匹配中提取客户/物品编号。

问题在于:我想排除日期,以便日期的前两个组成部分或最后两个组成部分不会被误解为客户/事项编号匹配。例如,如果我的字符串中有[^a-zA-Z0-9]*([a-zA-Z0-9]+[/\.\-]{1}[a-zA-Z0-9]+)[^a-zA-Z0-9]* - " Foo [1234-101] bar 456B / 102 baz 5/3/2016",我不想{{1成为一个匹配。为了解决这个问题,我首先尝试将5/3/2016添加到最终否定范围的末尾:

5/3/

这不起作用,因为我的量词/\.\-为零或更多,所以它只是将否定范围视为零次并且在[^a-zA-Z0-9]*([a-zA-Z0-9]+[/\.\-]{1}[a-zA-Z0-9]+)[^a-zA-Z0-9/\.\-]* 上匹配。接下来,我尝试制作它,使得否定范围要么出现一次或多次,要么遇到字符串的结尾:

*

然而,这恰好匹配5/3,这是有道理的。

如何调整模式以匹配一个实例但在重叠实例上失败?例如,我希望它与[^a-zA-Z0-9]*([a-zA-Z0-9]+[/\.\-]{1}[a-zA-Z0-9]+)([^a-zA-Z0-9/\.\-]+|$) 中的/3/20165/3中的foo 5/3 bar以及3/2016中的foo 3/2016 bar5/3/相匹配

3 个答案:

答案 0 :(得分:2)

(?<![\/\-\.a-zA-Z0-9])([a-zA-Z0-9]+[\/\-\.][a-zA-Z0-9]+)(?![\/\-\.a-zA-Z0-9])

按照您的要求完美运作,请参阅Regex101 demo

  

示例:Foo [ 1234-101 ]栏 456B/102 baz 5/3/2016

匹配: 1234-101 456B/102

  

示例:Foo [ 1234-101 ] bar 5/22/2016

匹配: 1234-101

答案 1 :(得分:0)

使用以下正则表达式:

[^\/0-9a-zA-Z]([0-9a-zA-Z]+[\/.-][0-9a-zA-Z]+)[^\/0-9a-zA-Z]

regexstorm's C# regex tester上的在线演示。

<强> 解释

  • 字符类([...])代表单个字符,因此量词{1}是多余的。

  • 您无需将完整的测试字符串与正则表达式匹配。如果您想这样做,请使用锚点(^$)作为分隔符。按照目前的情况,当指定全局匹配时,正则表达式引擎将匹配所有出现的模式。

  • 前导斜杠和尾随斜杠导致模式不匹配,从而保留日期字符串。

<强> 更新

  • C#regexen似乎不支持命名字符类,因此从速记中恢复。

  • 添加锚点作为目标模式的替代分隔符。因此,测试字符串开头或结尾的匹配将成功。

答案 2 :(得分:0)

An alternative以环视方式是wrong|(right)形式的消费模式,因此:

\d+\/\d+\/\d+|(\b\w+[-\/\.]\w+\b)

你匹配并吃掉(并忘记)你不想要的东西,\d+\/\d+\/\d+,然后在|之后的第二部分,匹配并记住你想要的东西,{{1 }}