在特殊条件下

时间:2017-06-16 08:57:44

标签: regex

我需要一种机制来查找字符串中的数字,该数字由非数字字符或字符串的开头/结尾或特殊分隔符(在本例中为43)包围。以下是一些例子:

  • order nr.12345678
  • 12345678
  • 12345678blabla
  • 431234567843

所有这些都应该导致匹配12345678。目前我正在使用以下正则表达式:

(?<=^|\D|43)([0-9]{8})(?=$|\D|43)

这个表达式效果很好,但有一个缺陷。如果数字以43开头但不以43结尾,我也得到肯定的结果。以下是我得到那些“错误”结果的例子:

  • 4312345678
  • 4312345678blabla

我现在需要的是正则表达式的构造,以便知道匹配的字符串是否以43开头,然后仅在结束时以43结尾才返回它。

2 个答案:

答案 0 :(得分:3)

您可以在lookbehind中使用正向前瞻检查:

(?<=^|\D|43(?=[0-9]{8}43))[0-9]{8}(?=43|\D|$)
           ^^^^^^^^^^^^^^

请参阅regex demo

现在,仅当43之前且在8个随机数字之后才会发生匹配。

<强>详情:

  • (?<=^|\D|43(?=[0-9]{8}43)) - 匹配字符串中的位置 之前是
    • ^ - 字符串开头
    • \D - 非数字符号
    • 43(?=[0-9]{8}43) - 43子字符串,后跟任意8位数字,然后是43 substring
  • [0-9]{8} - 正好是8位数
  • (?=43|\D|$) - 必须遵循8位数字:
    • 43 - 43数字序列
    • \D - (= [^0-9])任何非数字符号
    • $ - 字符串结束。

这是我自己的基于conditional的正则表达式,用于同一任务(可以在.NET,PCRE中使用,但不能在Java中使用):

(?<=^|[^0-9]|(43))[0-9]{8}(?=(?(1)43|(?:[^0-9]|$)))

这是一个RegexStorm demo,在测试.NET regexp时非常有用。

Conditional construct上的一些背景信息:

  

此语言元素尝试匹配两种模式中的一种,具体取决于它是否可以匹配初始模式。它的语法是:

     

(?( expression ) yes | no )

     

其中expression是要匹配的初始模式,yes是匹配表达式时要匹配的模式,如果表达式不匹配,则no是匹配的可选模式。正则表达式引擎将表达式视为零宽度断言;也就是说,正则表达式引擎在评估表达式后不会在输入流中前进。

因此,lookbehind中的(43)捕获转移到第1组,然后在条件(?(1)43|(?:[^0-9]|$))(?(1))内检查第1组是否匹配完全如果是,43匹配,否则尝试(?:[^0-9]|$)(任何非数字或字符串结尾。

答案 1 :(得分:2)

您可以使用conditional

(?<=^|\D|(43))[0-9]{8}(?(1)(?=43)|(?=$|\D))

在第1组中捕获第一个43,稍后在条件查询中捕获第1组是否与任何内容匹配。

如果你的正则表达式引擎不支持条件,你可以尝试这个“自己创建条件”解决方法:

(?<=^|\D|()43)[0-9]{8}(?=(?:\1(?:43)|(?!\1)(?:\D|$)))

我们的想法是用这样的替换替换条件(text)(?(1)a|b)()text(?:\1a|(?!\1)b)