正则表达式声明检查3个大写字母?

时间:2014-02-06 05:40:35

标签: python regex

我需要一个正则表达式,用于检查行中的3个大写字母。

例如,它应匹配:ABC,aABC,abcABC

但它不应该匹配:AaBbBc,ABCDE

目前这是我的陈述:

'[^A-Z]*[A-Z]{3}[^A-Z]*'

但这与ABCDE相符,我做错了什么?

提前致谢。

5 个答案:

答案 0 :(得分:5)

正则表达式

(?<![A-Z])[A-Z]{3}(?![A-Z])

说明

我分别在连续3个大写的中间正则表达式之前和之后指定了负前瞻和负前瞻。

与使用否定字符类相比,这是一个更好的选项,因为即使字符串的左侧或右侧没有字符,它也会成功匹配。

在线演示

DEMO


至于Python代码,我还没弄清楚如何打印出实际的匹配,
但这是语法:

使用re.match

>>> import re
>>> p = re.compile(r'(?<![A-Z])[A-Z]{3}(?![A-Z])')
>>> s = '''ABC
... aABC
... abcABCabcABCDabcABCDEDEDEDa
... ABCDE'''
>>> result = p.match(s)
>>> result.group()
'ABC'

使用re.search

>>> import re
>>> p = re.compile(r'(?<![A-Z])[A-Z]{3}(?![A-Z])')
>>> s = 'ABcABCde'
>>> p.search(s).group()
'ABC'

答案 1 :(得分:3)

在正则表达式中,开头和结尾的[^A-Z]*表示“查找任意数量的非大写字母,包括0。”因此,{{1}将满足你的正则表达式。例如,ABCDE可以被视为“0非大写字母”,后跟A,后跟BCD,也是“0非大写字母”。

我认为你想要做的是制作一个寻找的正则表达式:

  1. “非大写字母”是字符串的开头。
  2. 后跟“正好3个大写字母。”
  3. 跟随“非大写字母”结束我的字符串。
  4. 只要至少有1个大写字母在<3>大写字母之前或之后有多少非大写字母无关紧要。所以,你只需要寻找1。

    试试这个:

    E

    请注意,第一个(^|[^A-Z])[A-Z]{3}([^A-Z]|$) 表示字符串的开头,这与括号内^的含义不同。 ^表示字符串结束。

    在红宝石中测试过,这就是我们所拥有的:

    $

答案 2 :(得分:2)

你必须记住,当你使用正则表达式时,他们会尽可能多地尝试获得匹配(这也是正则表达式的最大弱点之一,这是通常导致catastrophic backtracking)的原因。这意味着你当前的正则表达式:

[^A-Z]*[A-Z]{3}[^A-Z]*

[A-Z]{3}匹配3个大写字母,[^A-Z]*两个都没有匹配(或空字符串)。您可以通过使用捕获组来了解如何:

import re
theString = "ABCDE"
pattern = re.compile(r"([^A-Z]*)([A-Z]{3})([^A-Z]*)")
result = pattern.search(theString)

if result:
    print("Matched string: {" + result.group(0) + "}")
    print("Sub match 1: {" + result.group(1) + "} 2. {" + result.group(2) + "} 3. {" + result.group(3) + "}")
else:
    print("No match")

打印:

Matched string: {ABC}
Sub match 1: {} 2. {ABC} 3. {}

ideone demo

你看到现在发生了什么吗?由于[^A-Z]*也可以接受“无”,这正是它尝试做的并匹配空字符串。

你可能想要的是使用更像这样的东西:

([^A-Z]|^)[A-Z]{3}([^A-Z]|$)

当它周围没有更多的大写字母时,它将匹配一个包含三个连续大写字母的字符串(|^表示OR在开头,|$表示OR在结尾处)。如果您在上面的小脚本中使用该正则表达式,则ABCDE中的任何匹配都不是您想要的。如果您在字符串abcABC上使用它,则会得到:

import re
theString = "abcABC"
pattern = re.compile(r"([^A-Z]|^)([A-Z]{3})([^A-Z]|$)")
result = pattern.search(theString)

if result:
    print("Matched string: {" + result.group(0) + "}")
    print("Sub match 1: {" + result.group(1) + "} 2. {" + result.group(2) + "} 3. {" + result.group(3) + "}")

打印:

Matched string: {cABC}
Sub match 1: {c} 2. {ABC} 3. {}

[^A-Z]实际上匹配(或者更好的正则表达式,消费)一个字符,如果你只关心检查字符串是否只包含一行中的3个大写字符,那么正则表达式就足够了。 / p>


如果要提取这些大写字符,可以使用上面示例中的捕获组,并使用result.group(2)来获取它。

实际上,如果你把一些捕获组变成非捕获组......

(?:[^A-Z]|^)([A-Z]{3})(?:[^A-Z]|$)

您可以使用result.group(1)获取这3个字母

否则,如果您不介意使用lookarounds(它们可能有点难以理解),您将不必使用捕获组。 Vasili的答案显示了你如何使用它们:

(?<![A-Z])[A-Z]{3}(?![A-Z])

(?<! ... )是负面的后视,如果内部模式与前一个字符匹配,则会阻止匹配。在这种情况下,如果前一个字符与[A-Z]匹配,则匹配将失败。

(?! ... )是一个负向前瞻,如果内部模式匹配下一个字符,将阻止匹配。在这种情况下,如果下一个字符与[A-Z]匹配,则匹配将失败。在这种情况下,您只需使用.group()来获取这些大写字母:

import re
theString = "abcABC"
pattern = re.compile(r"(?<![A-Z])[A-Z]{3}(?![A-Z])")
result = pattern.search(theString)

if result:
    print("Matched string: {" + result.group() + "}")

ideone demo

我希望它不会太长:)

答案 3 :(得分:0)

您可以使用:

    '^(?:.*[^A-Z])?[A-Z]{3}(?:[^A-Z].*)?$'

说明:

  • ^$匹配行的开头和结尾。
  • (?:.*[^A-Z])?检查前一个字符是否为大写字母(如果有)。

答案 4 :(得分:0)

你的正则表达式解释了你做错了什么

'[^A-Z]*[A-Z]{3}[^A-Z]*'

如果^在字符集中使用,即[],这意味着忽略,所以如果它在启动时启动一个或多个A-Z(大写字母),你的正则表达式将忽略。但按照你的例子,我认为你不想要那个

[A-Z] {3}表示它将完全匹配一行中的三个大写字母

[^ A-Z] *表示我对第一个解释的内容。

如果你只写'[A-Z] {3}',那么它会匹配字符串中任意位置的前三个连续大写字母。

它将匹配ABCde abCDE aBCDe ABCDE 但它不符合abcDE ABcDE AaBcCc

试试吧。 Perl中的示例

#!/usr/bin/perl
use strict;
use warnings;

my @arr = qw(AaBsCc abCDE ABCDE AbcDE abCDE ABC aABC abcABC);

foreach my $string(@arr){
  if($string =~ m/[A-Z]{3}/){
    print "Matched $string\n";
  }
  else {
    print "Didn't match $string \n";
  }
}

<强>输出:

Didn't match AaBsCc
Matched abCDE
Matched ABCDE
Didn't match AbcDE
Matched abCDE
Matched ABC
Matched aABC
Matched abcABC