在Python中查找正则表达式在字符串中匹配的次数

58
有没有一种方法可以在Python中查找字符串中正则表达式的匹配次数?例如,如果我有字符串"It actually happened when it acted out of turn."。我想知道"t a"出现了多少次。在该字符串中,"t a"出现了两次。我希望我的函数告诉我它出现了两次。这可能吗?

2
您是否需要计算重叠匹配?在字符串“friend of a friend of a friend”中,正则表达式“friend of a friend”出现一次还是两次? - Ants Aasma
2
你需要重叠吗?那么,如果匹配模式是“aa”,源字符串是“aaaa”,正确答案是3吗? - steveha
8个回答

66
import re
len(re.findall(pattern, string_to_search))

4
如果你不想错过大小写不同的模式,可以使用 len(re.findall(pattern, string_to_search, re.IGNORECASE))。 - KawaiKx

31

对于非重叠匹配,基于findall的现有解决方案很好(除了可能在匹配数量巨大时不是最优的)。如果您只关心计数而不使用列表,则可以使用其他选择,例如:sum(1 for m in re.finditer(thepattern, thestring))。使用subn并忽略结果字符串会有点特殊...:

def countnonoverlappingrematches(pattern, thestring):
  return re.subn(pattern, '', thestring)[1]

如果你只想计算(比如说)前100个匹配的话,那么后一种方法的唯一优势就在于这种情况下使用re.subn(pattern, '', thestring, 100)[1]可能更实用(无论有100次匹配还是1000次、甚至更多次都返回100)。

计算重叠的匹配需要你编写更多代码,因为相关的内置函数都专注于非重叠匹配。还有一个定义问题,例如如果pattern是'a+',thestring是'aa',你会认为这是一个匹配、三个匹配(第一个a,第二个a,或者都包含),还是其他什么?

假设你想要的是可能重叠的匹配,而且它们必须从字符串中不同的位置开始(这样对于前面那个例子会得到两个匹配):

def countoverlappingdistinct(pattern, thestring):
  total = 0
  start = 0
  there = re.compile(pattern)
  while True:
    mo = there.search(thestring, start)
    if mo is None: return total
    total += 1
    start = 1 + mo.start()
请注意,在这种情况下,您必须将模式编译为RE对象:函数re.search不接受start参数(搜索的起始位置),就像方法search一样。因此,您必须在进行搜索时对字符串进行切片——这肯定比让下一个搜索从下一个可能的不同起始点开始更费力,而这正是我在此函数中所做的。

20

我知道这是一个关于正则表达式的问题。我只是想提一下count方法,以备将来如果有人想要一个非正则表达式的解决方案。

>>> s = "It actually happened when it acted out of turn."
>>> s.count('t a')
2

返回子字符串非重叠出现次数的函数。


11

你可以通过使用非捕获子模式来查找重叠的匹配:

def count_overlapping(pattern, string):
    return len(re.findall("(?=%s)" % pattern, string))

问题的简单清晰的解决方案!谢谢。 - Tejas Anil Shah

10

你尝试过这个吗?

 len( pattern.findall(source) )

这是否计算重叠?他说它需要支持这个。(似乎这将非常难以执行) - Evan Fosmark
文档中写道:在字符串中返回模式的所有非重叠匹配项,作为字符串列表。http://docs.python.org/library/re.html - S.Lott

4
import re
print len(re.findall(r'ab',u'ababababa'))

2
为了避免创建匹配列表,可以使用re.sub与可调用对象一起使用。它将在每个匹配上被调用,并递增内部计数器。
class Counter(object):
    def __init__(self):
        self.matched = 0
    def __call__(self, matchobj):
        self.matched += 1

counter = Counter()
re.sub(some_pattern, counter, text)

print counter.matched

0

这个可以正常工作

ptr_str = lambda pattern,string1 :print(f'pattern = {pattern} times = {len(re.findall(pattern,string1))}')
pattern = 'AGATC'
str='AAGGTAAGTTTAGAATATAAAAGGTGAGTTAAATAGATCATAGGTTATATTGT'
ptr_str(pattern,string1)

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