所以我有以下正则表达式:
(?<!\.)\b([\w\@\-]+) *\b(IN|NOT IN|LIKE|NOT LIKE|BETWEEN|REGEXP|NOT|IS|XOR)+\b *
我希望它能帮助我匹配一些 SQL 代码。
但是,看起来我对第二个括号中的短语有问题,例如“不在”和“不喜欢”
我需要一个匹配或不匹配的正则表达式(没有像我当前正则表达式的工作方式那样的部分匹配)。
-
customers.id NOT IN (SELECT MAX(customers_service.customer_id))
根本不应该匹配 -
customers.id NOT LIKE (SELECT MAX(customers_service.customer_id))
根本不应该匹配 -
id NOT IN (SELECT MAX(customers_service.customer_id))
应该匹配 -
id IN (SELECT MAX(customers_service.customer_id))
应该匹配
我使用 RegexBuddy 进行检查,并使用我的正则表达式获得了 1 号和 2 号的匹配项。
另外,
-
id NOT IN (SELECT MAX(customers_service.customer_id))
仅匹配id NOT
,而不是id NOT IN
-
id NOT LIKE (SELECT MAX(customers_service.customer_id))
仅匹配id NOT
,而不是id NOT LIKE
我想修改这个正则表达式来捕获否定查找的条件,以及第二个括号中的确切短语,或者根本不匹配(无部分)。
我怎样才能完成这个工作?
最佳答案
首先,\b
与单词的开头或结尾不匹配。人们总是这么描述它,但这是一个谎言。什么\b
匹配是一个后跟单词字符但前面没有一个的位置-- (?=\w)(?<!\w)
-- 或者前面有一个单词字符,后面没有一个-- (?<=\w)(?!\w)
。如果这些条件不完全是您想要匹配的,那么您最好不要使用 \b
根本不。
您尝试匹配的名称显然可以包含 @
和-
以及标准的“单词”字符(字母、数字和下划线),因此单词边界毫无用处。一般来说,为了确保匹配完整的单词,您可以使用否定后向查找和否定先行查找:
(?<![\w@-])[\w@-]+(?![\w@-])
就您而言,您还需要确保前面的字符不是 .
,并且您知道以下字符必须是空格,因此正则表达式的该部分将是:
(?<![.\w@-])[\w@-]+\s+
更大的问题是,这也可能匹配您不想要的内容,即像 NOT
这样的关键字。和IN
。我建议两种补救措施。首先,收紧关键字的正则表达式,以便复合关键字,如 NOT IN
和NOT LIKE
被视为原子单位:
(?:NOT(?:\s+(?:IN|LIKE))?|IN|LIKE|BETWEEN|REGEXP|IS(?:\s+NOT)?|XOR)\b
其次,在前瞻中使用它来确保您匹配的第一个单词不是关键字(的一部分)。这是完整的正则表达式,为了可读性分为两行:
(?<![.\w@-])(?!(?:NOT(?:\s+(?:IN|LIKE))?|IN|LIKE|BETWEEN|REGEXP|IS|XOR)\b)[\w@-]+\s+
(?:NOT(?:\s+(?:IN|LIKE))?|IN|LIKE|BETWEEN|REGEXP|IS|XOR)\b\s*
您可以通过为关键字定义子例程组来使其更易于维护。这是 PHP 字符串文字的样子:
'~
(?(DEFINE)(?<KEYWORD>
(?:NOT(?:\s+(?:IN|LIKE))?|IN|LIKE|BETWEEN|REGEXP|IS(?:\s+NOT)?|XOR)\b
))
(?<![.\w@-])(?!(?&KEYWORD))[\w@-]+\s+(?&KEYWORD)\s*
~ix'
...这是一个 demo 。
关于php - 稍微复杂的正则表达式,用于匹配后面的否定外观,后跟一个精确的短语,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14072396/