代码之家  ›  专栏  ›  技术社区  ›  rory.ap

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

  •  1
  • rory.ap  · 技术社区  · 10 年前

    我正在尝试在.NET中编写一个正则表达式,它与客户机/物料编号相匹配。客户编号或事项编号由一系列字母或数字组成,客户/事项编号是客户编号和事项编号的组合,由 / , - . 例如 0204A/101 .

    在以下字符串中:

    Foo[1234/101]酒吧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 这很有道理。

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

    3 回复  |  直到 10 年前
        1
  •  2
  •   Ankit Singh    10 年前
    (?<![\/\-\.a-zA-Z0-9])([a-zA-Z0-9]+[\/\-\.][a-zA-Z0-9]+)(?![\/\-\.a-zA-Z0-9])
    

    正如你所要求的那样,效果完美 Regex101 demo


    示例:Foo[ 1234-101 ]巴 456B/102 baz 2016年5月3日

    比赛: 1234-101 456桶/102

    示例:Foo[ 1234-101 ]2016年5月22日酒吧

    比赛: 1234-101

        2
  •  0
  •   Scott Weaver    10 年前

    An alternative 环顾四周的方法是表单中的消费模式 wrong|(right) ,因此:

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

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

        3
  •  0
  •   collapsar    10 年前

    使用以下正则表达式:

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

    在线演示 regexstorm's C# regex tester .

    解释

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

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

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

    更新

    • C#regexen似乎不支持命名字符类,因此从简写恢复过来。

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