我需要使用正则表达式在简单表达式中查找所有操作。例如:
a+b*c/d
这里我们有3个操作。
像\d.*[\+\-\*\/].*\d
这样的正则表达式只返回两个匹配项。
有没有办法找到所有比赛?
答案 0 :(得分:9)
为了得到答案,我将以简单的步骤拆分它。
为简单起见,我们将数字定义为\d+
,表示匹配一位或多位数。如果您想要更全面的正则表达式,可以查看this answer。
要匹配数学运算符,我们可能会使用字符类[/*+-]
。如果将字符放入字符类中,则会失去正则表达式含义,因此[.]
只会匹配一个点。我们将使用与/
不同的分隔符,这样我们就不需要在表达式中转义/
。连字符-
通常用于定义字符范围 a-z
,但如果将其放在字符类的开头或结尾,则无需转义它
我们的正则表达式看起来像\d+\s*[/*+-]\s*\d+
。 \s*
可以选择匹配某些空格。
使用上述模式时,您会发现它只与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
所以我们的问题是当引擎完成一场比赛时,它将从最后一个字符位置+ 1继续,而我们希望它从第一个数字的末尾继续。
1+2*3/4
^^^ match and advance
1+2*3/4
^ continue from here ?
解决方案
我们需要一个zerowidth前瞻断言(?=)
。例如,a(?=b)
表示b
后a
为a
,然后匹配a
以便ab
匹配ac
但b
不匹配}}。这样做的好处是正则表达式引擎将从位置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
到目前为止一切都那么好但是当我们测试了一些其他数字时,我们得到了一些weird results。输入为12+3
,它在第1组中提供了两个结果,而不是一个2+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
。是什么原因?
好吧,让我们一步一步看看:
(?=(\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}}。