正确使用perl中负向前瞻表达式内的插入符号

mli*_*006 5 regex perl

我试图匹配任何不完全由大写字母或小写字母组成的单词,并且我有以下正则表达式:

if ($line =~ /(?!^[A-Z][A-Z]+(\s*)$)(?!^[a-z][a-z]+(\s*)$)/) {
    print $line;
}
Run Code Online (Sandbox Code Playgroud)

下面的表达式应匹配所有大写字母的单词

(?!^[A-Z][A-Z]+(\s*)$) 
Run Code Online (Sandbox Code Playgroud)

这应该匹配所有小写字母的单词

(?!^[a-z][a-z]+(\s*)$)
Run Code Online (Sandbox Code Playgroud)

我将两者结合起来并尝试将其与以下单词匹配:ASDSFSDF,asdfasdfasdf和asdasdfFFFdsfs.我注意到它匹配一切.只有当我将插入符号移动到括号外时,如下所示:

^(?![A-Z][A-Z]+(\s*)$)^(?![a-z][a-z]+(\s*)$)/)
Run Code Online (Sandbox Code Playgroud)

我是否认为它只能加工asdasdfFFFdsfs.有人可以向我解释为什么我需要将运算符移到负前瞻表达式之外吗?我是regexp的新手,我很困惑.

谢谢.

amo*_*mon 3

您陷入了多重否定和锚定的陷阱,并且您生成的正则表达式并没有完全达到您想要的效果。假设我们只有简化的正则表达式/(?!^[A-Z]$)/和字符串"1"

\n\n

在第一个位置(在 之前1),测试断言。这里匹配^,但[A-Z]不匹配。因此,^[A-Z] 失败了。由于前瞻为,整个模式成功。

\n\n

现在假设我们有字符串"A"。在第一个位置,测试断言。图案^[A-Z]$在这里匹配。因为它是负向前瞻,所以断言失败。

\n\n

然后,测试第二个位置(在 之后A)。该断言已被测试,但是^与此处 \xe2\x80\x93 不匹配,因此否定断言使模式成功!

\n\n

因此,您的正则表达式与您想要的模式不匹配。您可以通过锚定在断言之外来抑制此行为:

\n\n
/^(?![A-Z]$)/\n
Run Code Online (Sandbox Code Playgroud)\n\n

在这种情况下。请注意,在您的情况下,最简单的解决方案是编写一个与您不匹配的所有输入相匹配的正则表达式并否定该结果:

\n\n
print $line unless $line =~ /^(?:[A-Z]{2,}|[a-z]{2,})\\s*$/;\n
Run Code Online (Sandbox Code Playgroud)\n\n

(编辑:实际上 TLP 的第二个解决方案更简单,而且可能更有效)

\n