这是我曾经尝试过的最艰难的事情之一.多年来我一直在搜索,但我找不到这样做的方法 – 匹配一个不被给定字符包围的字符串,如引号或更大/小于符号.
像这样的正则表达式可以匹配不在HTML链接中的URL,不在引号中的sql table.column值以及许多其他内容.
Example with quotes: Match [THIS] and "something with [NOT THIS] followed by" or even [THIS]. Example with <,>,& " Match [URL] and <a href="[NOT URL]">or [NOT URL]</a> Example with single quotes: WHERE [THIS] LIKE '%[NOT THIS]'
基本上,当它没有被给定的char包围时,如何匹配字符串(THIS)?
\b(?:[^"'])([^"']+)(?:[^"'])\b
这是一个测试模式:像我想的那样的正则表达式只匹配第一个“引用”.
To quote,“quote me not lest I quote you!”
最佳解决方案取决于您对输入的了解.例如,如果您正在寻找未用双引号括起来的内容,这是否意味着双引号将始终正确平衡?他们可以用反斜杠逃脱,还是用单引号括起来?
假设最简单的情况 – 没有嵌套,没有转义 – 你可以使用这样的前瞻:
preg_match('/THIS(?=(?:(?:[^"]*+"){2})*+[^"]*+\z)/')
找到目标(THIS)后,前瞻基本上计算该点之后的双引号,直到字符串结束.如果它们有奇数,则匹配必须在一对双引号内发生,因此它无效(前瞻失败).
正如您所发现的,这个问题不适合正则表达式;这就是为什么所有提出的解决方案都依赖于真实正则表达式中没有的特征,比如捕获组,外观,不情愿和占有量词.没有possessive quantifiers或atomic groups,我甚至不会尝试这个.
编辑:要扩展此解决方案以考虑可以使用反斜杠转义的双引号,您只需要替换匹配“任何不是双引号”的正则表达式部分:
[^"]
“任何不是引用或反斜杠,或反斜杠后跟任何东西”:
(?:[^"\\]|\\.)
由于反斜杠转义序列相对较少,因此当您处于正则表达式的那一部分时,尽可能匹配尽可能多的非转义字符是值得的:
(?:[^"\\]++|\\.)
总而言之,正则表达式变为:
'/THIS\d+(?=(?:(?:(?:[^"\\]++|\\.)*+"){2})*+(?:[^"\\]++|\\.)*+$)/'
应用于您的测试字符串:
'Match THIS1 and "NOT THIS2" but THIS3 and "NOT "THIS4" or NOT THIS5" ' + 'but \"THIS6\" is good and \\\\"NOT THIS7\\\\".'
……它应匹配’THIS1′,’THIS3′,’THIS4’和’THIS6′.