正面表达与回顾

时间:2014-01-05 21:58:45

标签: regex

我需要使用正则表达式在简单表达式中查找所有操作。例如:

a+b*c/d

这里我们有3个操作。

  1. a + b
  2. B * C
  3. C / d
  4. \d.*[\+\-\*\/].*\d这样的正则表达式只返回两个匹配项。

    1. A + B
    2. C / d
    3. 有没有办法找到所有比赛?

1 个答案:

答案 0 :(得分:9)

为了得到答案,我将以简单的步骤拆分它。

1)匹配(数学)b

为简单起见,我们将数字定义为\d+,表示匹配一位或多位数。如果您想要更全面的正则表达式,可以查看this answer

要匹配数学运算符,我们可能会使用字符类[/*+-]。如果将字符放入字符类中,则会失去正则表达式含义,因此[.]只会匹配一个点。我们将使用与/不同的分隔符,这样我们就不需要在表达式中转义/。连字符-通常用于定义字符范围 a-z ,但如果将其放在字符类的开头或结尾,则无需转义它

我们的正则表达式看起来像\d+\s*[/*+-]\s*\d+\s*可以选择匹配某些空格。

Online demo

2)匹配(数学)b(数学)c(数学)d

使用上述模式时,您会发现它只与a (math) bc (math) d匹配,而我们也希望匹配b (math) c

问题

当正则表达式引擎使用以下表达式1+2*3/4时,让我们举一个简单的例子\d+\s*[/*+-]\d+

1+2*3/4
^^^ match and advance

1+2*3/4
   ^ no match

1+2*3/4
    ^^^ match and advance

Nothing to do

所以我们的问题是当引擎完成一场比赛时,它将从最后一个字符位置+ 1继续,而我们希望它从第一个数字的末尾继续。

1+2*3/4
^^^ match and advance

1+2*3/4
 ^ continue from here ?

解决方案

我们需要一个zerowidth前瞻断言(?=)。例如,a(?=b)表示baa,然后匹配a以便ab匹配acb不匹配}}。这样做的好处是正则表达式引擎将从位置b继续而不是位置ab ^ match and continue ab ^ no match + 1。

(?=(\d+\s*[/*+-]\d+))

我们可能会利用此功能并使用捕获组将所需结果“转储”到组中:1+2*3/4 ^ ^^^ match dump it in group 1 and continue 1+2*3/4 ^ no match 1+2*3/4 ^ ^^^ match dump it in group 1 and continue 1+2*3/4 ^ no match 1+2*3/4 ^ ^^^ match dump it in group 1 and continue 1+2*3/4 ^ no match 1+2*3/4 ^ no match The end

12+3

Online demo

3)出现了一个疯狂的问题

到目前为止一切都那么好但是当我们测试了一些其他数字时,我们得到了一些weird results。输入为12+3,它在第1组中提供了两个结果,而不是一个2+312+3 ^ ^^^^ match and dump it in group 1 and continue 12+3 ^ ^^^ match and dump it in group 1 and continue 12+3 ^ no match 12+3 ^ no match 。是什么原因?

好吧,让我们一步一步看看:

(?=(\d+\s*[/*+-]\d+))\d+
啊,看起来好像一步推进并不是好事。所以我们需要匹配一个数字12+3 ^^ ^^^^ match and dump it in group 1 and continue 12+3 ^ no match 12+3 ^ no match

~(?=(\d+\s*[/*+-]\d+))\d+~

对于TLDR来说有点迟,对某些语言使用g/修饰符。

根据语言的不同,您可能无法使用自定义分隔符,这意味着您需要在表达式中转义{{1}}。

Online demo