我正在尝试匹配以“deny”开头但不以“log”结尾的配置中的行。这看起来非常基本但我无法在我看过的众多论坛中找到我的解决方案。我的初学者心态让我尝试“^ deny。*(?!log $)”为什么这不起作用?我的理解是,它会找到以“deny”开头的任何字符串,后跟0或更多位数的任何字符,其中行尾不是log。
答案 0 :(得分:2)
当给出deny this log
之类的行时,您的^deny.*(?!log$)
正则表达式(我省略了示例问题中的空格)的计算方法如下:
^deny
匹配“deny”。.*
表示“匹配任何字符的0或更多”,因此它可以匹配“此日志”。^(?!log$)
表示“确保下一个字符不是'log',然后是行尾。”在这种情况下,他们不是 - 他们只是行的结尾 - 所以正则表达式匹配。请尝试使用此正则表达式:
^deny.*$(?<!log)
“在字符串的开头匹配拒绝,然后匹配到行的末尾,然后使用零宽度负面的后置断言来检查我们刚刚在行末尾匹配的内容是不是'log ”“。
所有这些都说......
正则表达不一定是这项工作的最佳工具。在这种情况下,一个简单的布尔运算符,如
if (/^deny/ and not /log$/)
可能比像
这样更高级的正则表达式更清晰if (/^deny.*$(?<!log)/)
答案 1 :(得分:1)
(?!log$)
是一个零宽度负向前瞻断言,表示如果字符串中此时此刻紧挨前是log
并且结束时不匹配字符串,但正则表达式中的.*
已经贪婪地消耗了字符串末尾的所有字符,因此log
无法匹配。
如果您的正则表达式实现支持后视,您可以使用正则表达式,例如在Josh Kelley的答案中,如果您使用的是javascript,则可以使用
/^deny(?:.{0,2}|.*(?!log)...)$/m
m
标志表示多行模式,这使得^
和$
匹配每行的开头和结尾,而不仅仅是字符串的开头和结尾。
请注意,三个.
位于否定前瞻之后,因此如果有log
,则它具有匹配.{0,2}
的空间。包括这三个点意味着还需要添加deny
选项,以便在(?:a|b)
之后具有0到2个字符的字符串也匹配。 {{1}}表示 a 或 b 必须匹配的非捕获组。