从正则表达式字符串中找到字符位置

0 投票
6 回答
2899 浏览
提问于 2025-04-16 10:17

假设我有一个字符串 'ABBACDA',我想找到每个字母 A 的位置。

如果我在 Python 中使用正则表达式,像这样:match = re.findall('A', 'ABBACDA'),这只会返回一个列表。

有没有什么办法可以调整一下这个方法?或者我应该换个思路?我想避免使用 for x in enumerate(str),因为我还想检查一下,比如 'BB' 在哪里,它的起始位置是什么。

6 个回答

0

你可以试着测一下下面这个方法的速度,看看它是否比正则表达式的方法更快:

def multifind(needle, haystack, overlap=False):
    delta = 1 if overlap else max(1, len(needle))
    pos = 0
    find = haystack.find
    while 1:
        pos = find(needle, pos)
        if pos < 0: return
        yield pos
        pos += delta

>>> data = 'ABBACDABBmmrteyBBgfrewBBBBBioBBytA BBB ggdAdbBB BBbGtBBABGtbBbGT'
>>> list(multifind('A', data))
[0, 3, 6, 33, 42, 55]
>>> list(multifind('BB', data))
[1, 7, 15, 22, 24, 29, 35, 45, 48, 53]
>>> list(multifind('BB', data, overlap=True))
[1, 7, 15, 22, 23, 24, 25, 29, 35, 36, 45, 48, 53]
>>> list(multifind('', 'qwerty'))
[0, 1, 2, 3, 4, 5, 6]
>>>
2

给约翰·马钦

« (1) 在你的“find”代码中,tof是“A”,在你的正则表达式代码中,tof是“BB” »

不对。 有一段“find”代码,tof是“A”, 还有一段代码是比较“find”方法和“regex”方法,tof是“BB”。并没有单独的“regex”代码,tof是“BB”。

这段“find”代码是单独展示这个解决方案的,目的是为了让它更清晰,因为在第二段代码中可读性被模糊了。

我把pat = re.compile(tof)的定义放在循环外面,是为了不把它创建的时间算在测量的时间里。因为它在第二段代码的开头,所以你以为这是完全的“regex”代码。其实不是。这是一段比较代码。

你应该更仔细地阅读。

« (2) ch[prec:].find(tof) 而不是 ch.find(tof, prec) »

没错。

其实我早就知道索引应该放在find()里,而不是用在字符串中。我发现了这个问题,并且在之前的代码中已经用过这种方式,只是当时脑子一片空白。

顺便说一下,这样代码就简单多了。其次,正如你指出的,修正后的“find”解决方案现在运行得更快。它在T秒内完成,而正则表达式的解决方案在0.77 * T(修正前是0.65 * T)内完成:

ch = 'jggBBjgjBBBjhgBBBBjjgBBBBBjjggBBBBBBjjjgjBBBBBBB'
tof = 'BB'
L = len(tof)

X,Y = [],[]
pat = re.compile(tof)

for essay in xrange(5):

    te = clock()
    for i in xrange(1000):
        li = []
        x = ch.find(tof)
        while x+1:
            li.append(x)
            x = ch.find(tof,x+L)
    X.append( clock()-te )


    te = clock()
    for i in xrange(1000):
        ly = [ m.start() for m in pat.finditer(ch) ]
    Y.append( clock()-te )

print li,'\n',ly,'\n'
print min(X),'\n',min(Y)

不过,这并不是一个戏剧性的加速:快了18%。

« (3) 你的find代码考虑了重叠匹配,而正则表达式代码没有 »

我不这么认为。我特意用包含“BBBBB”的字符串‘ABBACDABBmmrteyBBgfrewBBBBBioBByt BBB ggddbBB BBbGtBBBGtbBbGT’进行了测试,以验证“find”解决方案和“regex”解决方案给出的结果是一样的,因为我知道正则表达式不会返回重叠匹配。我使用L = len(tof)正是为了避免检测到重叠的切片。

上述代码的结果:

[3, 8, 14, 16, 21, 23, 30, 32, 34, 41, 43, 45]
[3, 8, 14, 16, 21, 23, 30, 32, 34, 41, 43, 45]

那么“你的find代码考虑了重叠匹配”是什么意思呢?

« (4) 等等 »

这不公平。如果有等等,请说明是哪一些。如果没有……好吧,我不知道……

我觉得一个正确的评论和一个错误的、可疑的、不公平的评论的比例是1:3,这样的情况不足以让我给出差评。

而且,在Stack Overflow上,我发现那些在问题发布后1或2小时内写出的不完美答案更容易被差评,而那些类似的好答案则更少被点赞,因为提问者早就找到了自己的解决方案。

5

使用 re.finditer() 方法

例子 1:

match = re.finditer('A', 'ABBACDA')
for m in match:
    print m.start(), m.end(), m.group(0)

输出结果:

0 1 A
3 4 A
6 7 A

例子 2:

match = re.finditer('BB', 'ABBACDA')
for m in match:
    print m.start(), m.end(), m.group(0)

输出结果:

1 3 BB

撰写回答