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

时间:2013-09-15 22:22:44

标签: regex perl

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

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

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

(?!^[A-Z][A-Z]+(\s*)$) 

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

(?!^[a-z][a-z]+(\s*)$)

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

^(?![A-Z][A-Z]+(\s*)$)^(?![a-z][a-z]+(\s*)$)/)

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

感谢。

3 个答案:

答案 0 :(得分:3)

你陷入了多次否定和锚定的陷阱,而你得到的正则表达并没有完全按照自己的意愿行事。假设我们只有简化的正则表达式/(?!^[A-Z]$)/和字符串"1"

在第一个位置(1之前),测试断言。此处^匹配,但[A-Z]不匹配。因此,^[A-Z] 失败。由于前瞻是否定,整个模式都会成功。

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

然后,测试第二个位置(在A之后)。测试断言,但^在这里不匹配 - 因此否定断言使模式成功!

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

/^(?![A-Z]$)/

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

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

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

答案 1 :(得分:3)

如何只检查字符串中的大小写字符?

(?=.*[A-Z])(?=.*[a-z])

如您所见,这与仅包含一个案例的字符串不匹配,因为两个前瞻必须匹配。

当然,这只是执行两个正则表达式匹配并组合结果的复杂方法:

if ($line =~ /[A-Z]/ and $line =~ /[a-z]/)

答案 2 :(得分:1)

这将匹配整个单词的混合案例:

^[[:alpha:]]*([[:upper:]][[:lower:]]|[[:lower:]][[:upper:]])[[:alpha:]]*$

小一点:

^[A-Za-z]*([A-Z][a-z]|[a-z][A-Z])[A-Za-z]*$