我需要使用正则表达式以简单表达式查找所有操作.例如:
a+b*c/d
这里我们有3个操作.
A + B
公元前
光盘
正则表达式\d.*[\+\-\*\/].*\d
只返回两个匹配.
A + B
光盘
有没有办法找到所有的比赛?
为了得到答案,我将以简单的步骤拆分它.
为简单起见,我们将定义一个数字\d+
,表示匹配一位或多位数.如果你想要一个更全面的正则表达式,你可以看一下这个答案.
为匹配数学运算符,我们可能使用字符类[/*+-]
.如果你将字符放在一个字符类中,它们会失去正则表达式的意思,所以[.]
只会匹配一个点.我们将使用不同的分隔符/
,这样我们就不需要/
在表达式中转义.连字符-
通常用于定义字符范围,a-z
但如果将其放在字符类的开头或结尾,则无需转义它.
我们的正则表达式看起来像\d+\s*[/*+-]\s*\d+
.\s*
是否可以选择匹配一些空格.
Online demo
使用上面的模式时,你会发现它只匹配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
+ 1.
ab ^ match and continue ab ^ no match
我们可能会利用它并使用捕获组将所需结果"转储"到一个组中:(?=(\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
Online demo
到目前为止一直很好,但是当我们测试其他数字时,我们得到了一些奇怪的结果.输入是12+3
,它给了我们两个结果在组1而不是一个12+3
和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
对于TLDR来说有点迟,请使用某些语言~(?=(\d+\s*[/*+-]\d+))\d+~
的g
修饰符.
根据语言的不同,您可能无法使用自定义分隔符,这意味着您需要/
在表达式中进行转义.
Online demo