使用Perl正则表达式将字符串切成可用的部分时,我需要匹配除某个模式之外的所有内容.我在Perl Monks上发现这个提示后解决了它:
/^(?:(?!PATTERN).)*$/; # Matches strings not containing PATTERN
Run Code Online (Sandbox Code Playgroud)
虽然我解决了我最初的问题,但我对它的实际工作方式一无所知.我检查了perlre,但它有点太正式无法掌握.
正则表达式匹配不包含单词的行?有很多理解,但为什么.在我的例子和?:外括号如何工作?
有人可以打破正则表达式并用简单的词语解释它是如何工作的吗?
yst*_*sth 14
逐个构建它(并且在整个假设字符串或PATTERN中没有换行符):
这匹配任何字符串:
/^.*$/
Run Code Online (Sandbox Code Playgroud)
但是我们不想.匹配开始PATTERN的字符,所以替换
.
Run Code Online (Sandbox Code Playgroud)
同
(?!PATTERN).
Run Code Online (Sandbox Code Playgroud)
这使用负向前瞻,测试给定模式而不实际消耗任何字符串,只有在模式在字符串中的给定点不匹配时才成功.所以就像说:
if PATTERN doesn't match at this point,
match the next character
Run Code Online (Sandbox Code Playgroud)
这需要对字符串中的每个字符进行,因此*用于匹配从字符串的开头到结尾的零次或多次.
为了*适用于负面预测的组合.,而不仅仅是.,它需要被括号括起来,并且因为没有理由捕获,所以它们应该是非捕获括号(?: ):
(?:(?!PATTERN).)*
Run Code Online (Sandbox Code Playgroud)
并放回锚点以确保我们测试字符串中的每个位置:
/^(?:(?!PATTERN).)*$/
Run Code Online (Sandbox Code Playgroud)
请注意,此解决方案作为更大匹配的一部分特别有用; 例如,匹配任何字符串,foo以及之后baz但不在bar之间:
/foo(?:(?!bar).)*baz/
Run Code Online (Sandbox Code Playgroud)
如果没有这些考虑因素,您可以简单地做:
/^(?!.*PATTERN)/
Run Code Online (Sandbox Code Playgroud)
检查PATTERN与字符串中的任何位置是否匹配.
关于换行符:正则表达式和换行符存在两个问题.首先,.不匹配换行符,因此"foo\nbar" =~ /^(?:(?!baz).)*$/不匹配,即使该字符串不包含baz.您需要添加/ s标志以.匹配任何字符; "foo\nbar" =~ /^(?:(?!baz).)*$/s正确匹配.第二,$只是在字符串的末尾不匹配,它也可以在字符串末尾的换行符之前匹配.所以"foo\n" =~ /^(?:(?!\s).)*$/s确实匹配,即使该字符串包含空格,你正试图只匹配字符串,没有空格; \z始终只在最后匹配,所以"foo\n" =~ /^(?:(?!\s).)*\z/s正确地无法匹配实际上包含a的字符串\s.所以正确的通用正则表达式是/^(?:(?!PATTERN).)*\z/s