5

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

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。有人可以向我解释为什么我需要将运算符移到负前瞻表达式之外?我是正则表达式的新手,我很困惑。

谢谢。

4

3 回答 3

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 的第二个解决方案更简单,而且可能更有效)

于 2013-09-15T22:46:04.677 回答
3

只检查字符串的大小写字符怎么样?

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

如您所见,这不会匹配仅包含一种情况的字符串,因为两个前瞻必须匹配。

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

if ($line =~ /[A-Z]/ and $line =~ /[a-z]/)
于 2013-09-15T22:46:55.603 回答
1

这将匹配整个单词的混合大小写:

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

小一点:

^[A-Za-z]*([A-Z][a-z]|[a-z][A-Z])[A-Za-z]*$
于 2013-09-15T22:28:55.200 回答