正面表达与回顾

Bar*_*try 2 regex

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

a+b*c/d
Run Code Online (Sandbox Code Playgroud)

这里我们有3个操作.

  1. A + B
  2. 公元前
  3. 光盘

正则表达式\d.*[\+\-\*\/].*\d只返回两个匹配.

  1. A + B
  2. 光盘

有没有办法找到所有的比赛?

Ham*_*mZa 9

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

1)匹配(数学)b

为简单起见,我们将定义一个数字\d+,表示匹配一位或多位数.如果你想要一个更全面的正则表达式,你可以看一下这个答案.

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

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

Online demo

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

使用上面的模式时,你会发现它只匹配a (math) b,c (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
Run Code Online (Sandbox Code Playgroud)

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

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

1+2*3/4
 ^ continue from here ?
Run Code Online (Sandbox Code Playgroud)

解决方案

我们需要一个zerowidth前瞻断言(?=).例如a(?=b)意味着如果有ba,再搭配a所以a得到匹配的ab,但不是ac.这样做的好处是正则表达式引擎将从位置继续b而不是位置b+ 1.

ab
^ match and continue

ab
 ^ no match
Run Code Online (Sandbox Code Playgroud)

我们可能会利用它并使用捕获组将所需结果"转储"到一个组中:(?=(\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
Run Code Online (Sandbox Code Playgroud)

Online demo

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

到目前为止一直很好,但是当我们测试其他数字时,我们得到了一些奇怪的结果.输入是12+3,它给了我们两个结果在组1而不是一个12+32+3.什么原因 ?

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

12+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
Run Code Online (Sandbox Code Playgroud)

啊看起来像一步推进并不是一件好事.所以我们需要匹配一个数字(?=(\d+\s*[/*+-]\d+))\d+!

12+3
^^
^^^^ match and dump it in group 1 and continue

12+3
  ^ no match

12+3
   ^ no match
Run Code Online (Sandbox Code Playgroud)

对于TLDR来说有点迟,请使用某些语言~(?=(\d+\s*[/*+-]\d+))\d+~g修饰符.

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

Online demo