【问题标题】:Regular expression for excluding overlapping matches用于排除重叠匹配的正则表达式
【发布时间】:2016-05-04 15:09:37
【问题描述】:

我正在尝试在 .NET 中编写一个匹配客户/事务编号的正则表达式。客户编号或案件编号由一系列字母或数字组成,客户/案件编号是客户编号和案件编号的组合,由/-. 分隔。例如0204A/101

在以下字符串中:

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

我希望它与 [1234-101]456B/102 匹配。为此,我想出了这种模式:

[^a-zA-Z0-9]*([a-zA-Z0-9]+[/\.\-]{1}[a-zA-Z0-9]+)[^a-zA-Z0-9]*

我可以使用捕获组从每个匹配项中提取客户/事项编号。

问题是:我想排除日期,以便日期的前两个部分或后两个部分不会被误解为客户/事项编号匹配。例如,如果我的字符串中有 5/3/2016 ——“Foo [1234-101] bar 456B/102 baz 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/2016,这是有道理的。

如何调整我的模式以匹配一个实例但在重叠实例上失败?例如,我希望它匹配foo 5/3 bar 中的5/3foo 3/2016 bar 中的3/2016,但不匹配foo 5/3/2016 bar 中的5/3//3/2016

【问题讨论】:

  • 解释否决票。

标签: .net regex


【解决方案1】:
(?<![\/\-\.a-zA-Z0-9])([a-zA-Z0-9]+[\/\-\.][a-zA-Z0-9]+)(?![\/\-\.a-zA-Z0-9])

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


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

匹配项:1234-101456B/102

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

匹配:1234-101

【讨论】:

  • 谢谢。不幸的是,它不能很好地工作。试试“Foo [1234/101] bar 5/22/2016”,你就会明白我的意思了。
  • 谢谢,但它仍然不匹配字符串末尾的任何内容,例如“Foo 1234/101”。
  • 我在谈论您在上次编辑中添加环视之前的那个。这个:[^\/\-\.a-zA-Z0-9]([a-zA-Z0-9]+[\/\-\.][a-zA-Z0-9]+)[ ^\/\-\.a-zA-Z0-9]
  • 只是抓住了机会 :)
【解决方案2】:

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

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

你明确地匹配并吃掉(然后忘记)你不想要的东西,\d+\/\d+\/\d+,然后在 | 之后的第二部分,匹配并记住你想要的东西,(\b\w+[-\/\.]\w+\b)

【讨论】:

    【解决方案3】:

    使用以下正则表达式:

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

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

    解释

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

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

    • 前导和尾随斜杠会导致模式不匹配,从而将日期字符串排除在外。

    更新

    • C# 正则表达式似乎不支持命名字符类,因此从简写中恢复。

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

    【讨论】:

    • 我用foo 5/3 对此进行了测试,它与5/3 匹配,这让我很惊讶。如果您的模式中的最后一个 [^\/] 应该匹配“恰好一个非正斜杠”,那么为什么它匹配字符串末尾的输入?
    • 好吧,我意识到发生了什么:foo 5/3 之后有一个换行符,所以它与换行符匹配(因为它不是 /)。因此,当字符串以我想要匹配的内容结尾时,此模式不起作用,例如如果我的字符串由foo 5/3 组成并且我想匹配5/3
    • 谢谢,不过还是不太对劲。它与5/22/2016 中的5/22 匹配:regexstorm.net/…
    • 是的,你是对的。如果不复制分隔符类中允许的 ID 字符或求助于环视,它将无法可靠地工作。已更正。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-09-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-12-11
    • 2010-09-24
    相关资源
    最近更新 更多