我需要使用正则表达式以简单表达式查找所有操作.例如:
a+b*c/d
Run Code Online (Sandbox Code Playgroud)
这里我们有3个操作.
正则表达式\d.*[\+\-\*\/].*\d只返回两个匹配.
有没有办法找到所有的比赛?
为了得到答案,我将以简单的步骤拆分它.
为简单起见,我们将定义一个数字\d+,表示匹配一位或多位数.如果你想要一个更全面的正则表达式,你可以看一下这个答案.
为匹配数学运算符,我们可能使用字符类[/*+-].如果你将字符放在一个字符类中,它们会失去正则表达式的意思,所以[.]只会匹配一个点.我们将使用不同的分隔符/,这样我们就不需要/在表达式中转义.连字符-通常用于定义字符范围,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
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)意味着如果有b后a,再搭配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)
到目前为止一直很好,但是当我们测试其他数字时,我们得到了一些奇怪的结果.输入是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
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修饰符.
根据语言的不同,您可能无法使用自定义分隔符,这意味着您需要/在表达式中进行转义.