如何使用正则表达式进行反向搜索?

15
例如:
我的字符串是:123456789 nn nn oo nn nn mlm nn203
我的目标是:nn
然后,我从后往前匹配字符串,并返回第一个匹配结果及其位置。
在这个例子中,结果是nn,开始位置为[-5],结束位置为[-3]。
我写了一个简单的函数来执行此过程,但如何使用正则表达式来完成这项工作?

如果搜索词是“na”,您希望它在字符串中向前匹配还是向后匹配(即匹配man或name)? - Joachim Isaksson
3个回答

21

对于字符串本身,只需执行一次findall并使用最后一个结果:

import re

st='123456 nn1 nn2 nn3 nn4 mlm nn5 mlm'
 
print(re.findall(r'(nn\d+)',st)[-1])

打印出nn5

你也可以使用finditer来完成同样的事情,这会更容易地找到相关的索引:

print([(m.group(),m.start(),m.end()) for m in re.finditer(r'(nn\d+)',st)][-1])

打印('nn5', 27, 30)


如果有很多匹配项,而你只需要最后一个,有时候将字符串和模式反转是有意义的:

m=re.search(r'(\d+nn)',st[::-1])
offset=m.start(1)
print(st[-m.start(1)-len(m.group(1)):-m.start(1)])

或者,将您的模式修改为仅最后一次匹配可能满足的内容:
# since fixed width, you can use a lookbehind:
m=re.search(r'(...(?<=nn\d)(?!.*nn\d))',st)
if m: print(m.group(1))

或者,利用贪婪模式的 .*,它总是返回多个匹配中的最后一个:

# .* will skip to the last match of nn\d
m=re.search(r'.*(nn\d)', st)
if m: print(m.group(1))

任何这些打印品都包含nn5


这里有一个类似于你的代码,许多人可能认为更易读:http://pastebin.com/J7SsXjsS(请注意,在循环结束后`search`仍然存在。) - Brōtsyorfuzthrāx
在我给出的链接中,如果你没有得到任何结果,你会收到一个错误提示(所以一定要处理它)。 - Brōtsyorfuzthrāx
反转字符串是我需要的想法。 - grantr

7

首先,如果您不需要正则表达式,请使用string.rfind更容易正确实现。

您可以通过使用负向前瞻来使用正则表达式,请参阅re文档:

import re
s = "123456789 nn nn oo nn nn mlm nn203"
match = re.search("(nn)(?!.*nn.*)", s)

# for your negative numbers:
print (match.start()-len(s), match.end()-len(s))
# (-5, -3)

我建议在这里使用re.DOTALL标志,因为默认情况下,点字符(.)不包括换行符。 - NemPlayer

4

想法:

  • 在反向字符串中查找反向正则表达式(在您的情况下无关紧要)
  • 将结果索引转换为负数+切换开始<->结束

示例:

>>> import re
>>> s = "123456789 nn nn oo nn nn mlm nn203"
>>> m = re.search("(nn)", s[::-1])
>>> -m.end(), -m.start()
(-5, -3)

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