如何从字符串的某个索引使用 re.search?
这看起来是个简单的问题,但我没搞明白。我该怎么在一个字符串的中间开始搜索呢?
1 个回答
re.search
函数和字符串方法不一样,它不接受 start
这个参数。但是,编译后的正则表达式对象的 search
方法是可以接受 pos
参数的。
这样理解是有道理的。如果你需要反复使用同样的正则表达式,实际上你应该先编译它们。这样做不仅是为了提高效率(大多数应用中缓存效果很好),更是为了让代码更易读。
那么,如果你需要使用顶层函数,但因为某些原因不能预先编译你的模式,该怎么办呢?
其实有很多第三方的正则表达式库。有些库是基于 PCRE 或 Google 的 RE2 或 ICU,有些则是从头开始实现正则表达式,它们的 API 都有些不同,有的甚至差别很大。
不过,regex
模块正在被设计成最终替代标准库中的 re
,虽然它还没有完全准备好,但基本上可以直接替代 re
,而且它的 search
函数支持 pos
和 endpos
参数。
通常,你想这样做的最常见原因是“找到我刚找到的那个匹配之后的下一个匹配”,其实有更简单的方法:使用 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)
如果我给它 abcdefabcdef
,它会在第 3 个字符后匹配到第一个 'abc'
,也就是第二个 abc
。
但要注意,它实际上匹配的是 'defabc'
。因为我在使用捕获组来处理我的真实模式,而没有把 .{3}
放在一个组里,所以 match.group(1)
等等会按我想要的那样工作,但 match.group(0)
会给我错误的结果。如果这很重要,你需要使用后视查找。