我需要一个正则表达式,用于检查行中的3个大写字母。
例如,它应匹配:ABC,aABC,abcABC
但它不应该匹配:AaBbBc,ABCDE
目前这是我的陈述:
'[^A-Z]*[A-Z]{3}[^A-Z]*'
但这与ABCDE相符,我做错了什么?
提前致谢。
答案 0 :(得分:5)
(?<![A-Z])[A-Z]{3}(?![A-Z])
我分别在连续3个大写的中间正则表达式之前和之后指定了负前瞻和负前瞻。
与使用否定字符类相比,这是一个更好的选项,因为即使字符串的左侧或右侧没有字符,它也会成功匹配。
至于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个大写字母在<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. {}
你看到现在发生了什么吗?由于[^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() + "}")
我希望它不会太长:)
答案 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