否定正则表达式中的特定组

Negate a specific group in regular expressions

如何获取不包含特定组的字符串?

(?:[0-9-+*/()x]|abs|pow|ln|pi|e|a?(sin|cos|tan)h?)+

以上字符串是数学表达式的正则表达式。怎么得到不是数学表达式的字符串?

示例输入字符串:WIDTH+LENGTH*abs(2)

预期输出:WIDTHLENGTH

您可以在否定前瞻中使用正则表达式,然后添加 \w shorthand class 来匹配字母数字符号,或者 [a-zA-Z]\b 字边界:

(?![0-9-+*/()x]|abs|pow|ln|pi|e|a?(?:sin|cos|tan)h?)\b[a-zA-Z]+\b

regex demo

因为我们只允许带有 [a-zA-Z] 的字母,我们可以进一步减少到

(?!x|abs|pow|ln|pi|e|a?(?:sin|cos|tan)h?)\b[a-zA-Z]+\b

another demo

虽然 在大多数情况下可能有效,但它并不是问题中正则表达式的真正反转,因为有些事情两个正则表达式都不匹配:

  • 空间
  • 特殊字符,例如 ?!^~;:_,.[]{}<>(可能更多)。

以及两个正则表达式匹配的事情:

  • 字符串,例如 axabs(3),其中 xabs 部分与两者匹配。

这可能可以通过摆弄来解决,但是该死,我想要一个 actual 反转! :P

这里是:

(?:(?!e|ln|(?<=l)n|pi|(?<=p)i|abs|(?<=a)bs|(?<=ab)s|pow|(?<=p)ow|(?<=po)w|sin|(?<=s)in|(?<=si)n|cos|(?<=c)os|(?<=co)s|tan|(?<=t)an|(?<=ta)n|asin|acos|atan)[^0-9-+*/()x])+

它是这样工作的:

  1. 匹配不是 0-9-+*/()x (= [^0-9-+*/()x])之一的任何字符。
  2. 但不匹配那个字符,如果它匹配 preceeding/following 个字符的特定模式,并且它本身就是某个字符。
    使用否定前瞻((?!...))意味着每个|之后的第一个字符是当前字符,之后的字符是当前字符之后的字符,而(?<=)是否定的向后看,匹配某些前面的字符。
    所以,例如,为了匹配sin,我们需要"not match"s如果后面跟着in,不匹配i 如果前面是 s,后面是 n,如果前面是 si,则不匹配 n
    在正则表达式中(仅环视部分):(?!sin|(?<=s)in|(?<=si)n)
    构建 elnpi 等的完整列表会导致:

    (?!e|ln|(?<=l)n|pi|(?<=p)i|abs|(?<=a)bs|(?<=ab)s|pow|(?<=p)ow|(?<=po)w|sin|(?<=s)in|(?<=si)n|cos|(?<=c)os|(?<=co)s|tan|(?<=t)an|(?<=ta)n|asin|acos|atan)
    
  3. 匹配以上一次或多次((?:...)+).

通过将 (?<=l)n(?<=si)n(?<=ta)n 等部分合并到 (?<=l|si|ta)n 中,正则表达式可以缩短一点:

(?:(?!e|ln|(?<=l|si|ta)n|pi|(?<=p)i|abs|(?<=a)bs|(?<=ab|co)s|pow|(?<=p)ow|(?<=po)w|a?(?:sin|cos|tan)|(?<=s)in|(?<=c)os|(?<=t)an)[^0-9-+*/()x])+

可以查看此演示以及漂亮的可视化 on Debuggex

注意 1:此正则表达式在 JavaScript 中不起作用,因为 JS-regex 不支持 lookbehind。
注意 2:在 Debuggex 中将单个多字节字符(例如 §°☀☁️❄️)附加到测试字符串似乎会破坏它,但这不是我的正则表达式的问题,可以验证 with PHP, for example.

当你想要 "skip" 某些表达式时,这里就是你在正则表达式中所做的:

"Tarzan"|skip1|skip2|skip3|more|complicated|expressions|here|(Tarzan)

... 就像 The Best Regex Trick Ever.

一样简单

当您迭代正则表达式匹配集合时,您只需要第一个捕获组中包含任何内容的匹配,而忽略任何其他匹配。

无需使用通常不适用于重叠边缘情况的复杂环视。