如何从字符串的某个索引使用 re.search?

15 投票
1 回答
10751 浏览
提问于 2025-04-28 05:09

这看起来是个简单的问题,但我没搞明白。我该怎么在一个字符串的中间开始搜索呢?

暂无标签

1 个回答

18

re.search 函数和字符串方法不一样,它不接受 start 这个参数。但是,编译后的正则表达式对象的 search 方法是可以接受 pos 参数的。

这样理解是有道理的。如果你需要反复使用同样的正则表达式,实际上你应该先编译它们。这样做不仅是为了提高效率(大多数应用中缓存效果很好),更是为了让代码更易读。


那么,如果你需要使用顶层函数,但因为某些原因不能预先编译你的模式,该怎么办呢?

其实有很多第三方的正则表达式库。有些库是基于 PCRE 或 Google 的 RE2 或 ICU,有些则是从头开始实现正则表达式,它们的 API 都有些不同,有的甚至差别很大。

不过,regex 模块正在被设计成最终替代标准库中的 re,虽然它还没有完全准备好,但基本上可以直接替代 re,而且它的 search 函数支持 posendpos 参数。


通常,你想这样做的最常见原因是“找到我刚找到的那个匹配之后的下一个匹配”,其实有更简单的方法:使用 finditer 而不是 search

比如,这段字符串方法的循环:

i = 0
while True:
    i = s.find(sub, i)
    if i == -1:
        break
    do_stuff_with(s, i)

… 可以转换成这个更简洁的正则表达式循环:

for match in re.finditer(pattern, s):
    do_stuff_with(match)

如果这样做不合适,你也可以直接对字符串进行切片:

match = re.search(pattern, s[index:])

不过,这样会额外复制一半的字符串,如果 string 实际上是一个 12GB 的 mmap 文件,那就可能会有问题。(当然,对于 12GB 的 mmap 文件,你可能想要映射一个新的窗口……但有些情况下这样做也未必有帮助。)


最后,你也可以修改你的模式,跳过 index 个字符:

match = re.search('.{%d}%s' % (index, pattern), s)

我在模式的开头加了 .{20},这意味着匹配任意 20 个字符,加上你想匹配的其他内容。这里有个简单的例子:

.{3}(abc)

正则表达式可视化

Debuggex 演示

如果我给它 abcdefabcdef,它会在第 3 个字符后匹配到第一个 'abc',也就是第二个 abc

但要注意,它实际上匹配的是 'defabc'。因为我在使用捕获组来处理我的真实模式,而没有把 .{3} 放在一个组里,所以 match.group(1) 等等会按我想要的那样工作,但 match.group(0) 会给我错误的结果。如果这很重要,你需要使用后视查找。

撰写回答