正则表达式匹配偶数个字母

21

我需要在Python中使用正则表达式匹配仅匹配偶数字母出现次数的表达式。例如:

AAA        #不匹配
AA         #匹配
fsfaAAasdf #匹配
sAfA       #匹配
sdAAewAsA  #匹配
AeAiA      #不匹配

应该匹配偶数个A。


1
你想匹配某个特定字母的数量吗?或者任何字母,但对于字符串中找到的每个字母,它必须出现偶数次? - Ross Rogers
另外,我不太确定你的例子中是否有模式。是单词的开头和结尾吗? - Ross Rogers
1
为什么"sAfA"不匹配?这里有两个A,2是一个偶数。 - PaulMcG
你想确保至少有一对AA吗?换句话说,foo应该匹配还是不匹配? - Mark Byers
1
你的问题过于模糊。看看 """sdAAewAAs # match""" ... 你是指一个匹配 ("AAewAA") 还是两个匹配 (每个都是 "AA")?你想要偶数个字母,但是你尝试使用 "A*",它(显然?)匹配 "", "A", "AA", "AAA" 等等 -- 嗯?请注意,0 是一个偶数。 - John Machin
显示剩余2条评论
8个回答

29

尝试使用这个正则表达式:

^[^A]*((AA)+[^A]*)*$

如果A不需要连续:

^[^A]*(A[^A]*A[^A]*)*$

2
+1 看起来正确 - 查找任意数量的非-A字符,后跟AA对和其他字符之间。但是,如果(AA)*是(AA)+ ^ [^A] *((AA)+ [^A] $,则效率会略有提高。如果原始帖子想要“ab”不匹配正则表达式,则需要在末尾加上+,即^ [^A] *((AA)+ [^A] *)+ $以强制至少一对。 - Tom Leys
1
第二个版本可以改写为^([^A]A[^A]A[^A])$吗? - artburkart
@Chachi-inactive 可以的,但我想避免不必要的回溯。 - Gumbo

4
为什么要费力地设计一个难以阅读的模式呢?只需搜索所有出现的模式并计算找到了多少次即可。
len(re.findall("A", "AbcAbcAbcA")) % 2 == 0

这应该对所有有经验的程序员来说都是即刻可懂的,而像“(?

简单就是更好。

”这样的模式则不如此直观易懂。


因为它更快、更可重用、更紧凑、更酷。此外,这是我的问题,我不是在问最好的方法,只是如何使用正则表达式来实现它。 - Andriy Drozdyuk
5
更快?你怎么知道的?更可重用?有争议。更紧凑?不如易读重要。更酷?谁在意呢?几年后,你可能会后悔需要重新访问一些“酷”的代码。 至于你评论的最后部分,我同意——你没有要求最佳方式。对于像我这样的普通人来说很难判断,因为大多数人最终都想要最佳解决方案,只是不知道如何表达,所以像我这样的人通常会试图引导人们走我们认为是正确的方向。 - Bryan Oakley

3

这个搜索会查找一个包含奇数个A的块。如果找到了,那么这个字符串对你来说是不好的:

(?<!A)A(AA)*(?!A)

如果我理解正确,Python代码应该如下所示:
if re.search("(?<!A)A(AA)*(?!A)", "AeAAi"):
   print "fail"

2

'A*' 表示匹配任意数量的 A,甚至可以是 0。

以下是如何匹配一个具有偶数个大写或小写字母 a 的字符串:

re.compile(r'''
    ^
    [^a]*
    (
        (
            a[^a]*
        ){2}
    # if there must be at least 2 (not just 0), change the
    # '*' on the following line to '+'
    )* 
    $
    ''',re.IGNORECASE|re.VERBOSE)

你可能正在使用a作为示例。如果你想匹配除了a之外的特定字符,请将a替换为%s,然后插入。

[...]
$
'''%( other_char, other_char, other_char )
[...]

1
0也是一个偶数。但我怀疑像“(AA)+”这样的表达更符合OP的要求。 - PaulMcG
1
哎呀,我刚刚重新阅读了原帖的测试用例,他也想要非连续的字母。最好还是遍历字符串并计数。 - PaulMcG
1
实际上,再读一遍,看起来他想要匹配一个字符串中有双个A,并且没有任何单个A的情况。 - Anon.
匹配0个A是一个重言式。 - Alex Brown
问题的提问者最初询问为什么他的 a* 正则表达式会匹配像 bb 这样的字符串。有时候匹配 0 个 a 并不是非常明显 :-) - Ross Rogers

1

'*' 表示 0 或多个出现次数 使用 'AA' 应该可以解决问题。

问题是你是否想匹配 'AAA'。在这种情况下,你需要做一些像这样的事情:

r = re.compile('(^|[^A])(AA)+(?!A)',)
r.search(p)

这对于匹配偶数个“ A”(仅限偶数)将起作用。

现在,如果您想匹配“连续字母中有任何偶数个”,则可以使用以下方法:

re.compile(r'(.)\1')

然而,这并不排除“奇怪”的情况。但从你的问题中并不清楚你是否真的想要那样做。

更新: 这对于你的测试用例有效:

re.compile('^([^A]*)AA([^A]|AA)*$')

0
首先,注意到/A*/匹配空字符串。
其次,有一些事情是你无法通过正则表达式来实现的。如果你只是遍历字符串并计算出所寻找的字母的所有出现次数,这将会更加容易。

是的,更容易和更快。但是正则表达式太有趣了。 - Tom Leys

0

A* 表示匹配零个或多个 "A"。

对于偶数个 "A",尝试使用:(AA)+


这将仅匹配包含一对但也包含非一对的字符串,即AlalaAA将匹配。 - Tom Leys

0

使用正则表达式无法任意计数。例如,确保匹配括号。要进行计数,需要“记忆”,这需要像下推自动机一样强大的东西,尽管在这种情况下,您可以使用@Gumbo提供的正则表达式。

使用finditer是一般情况下最好的解决方法。


1
然而,这个问题并不需要匹配。他并不像要求有像A和B一样多的数量或类似的计数问题。 - Tom Leys

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接