Roe*_*ler 28 python regex string substring
我有一个可能的子串列表,例如['cat','fish','dog'].实际上,该列表包含数百个条目.
我正在处理一个字符串,我正在寻找的是找到任何这些子字符串的首次出现的索引.
为了澄清,对于'012cat',结果是3,对于'0123dog789cat',结果是4.
我还需要知道找到了哪个子字符串(例如,它在子字符串列表中的索引或文本本身),或者至少是匹配的子字符串的长度.
有明显的蛮力方法来实现这一点,我想知道是否有任何优雅的Python/Regex解决方案.
谢谢,Rax
Tom*_*Tom 33
我认为正则表达式比单独检查每个子字符串更好,因为从概念上讲,正则表达式被建模为DFA,因此在消耗输入时,所有匹配都在同时进行测试(导致输入字符串的一次扫描) ).
所以,这是一个例子:
import re
def work():
to_find = re.compile("cat|fish|dog")
search_str = "blah fish cat dog haha"
match_obj = to_find.search(search_str)
the_index = match_obj.start() # produces 5, the index of fish
which_word_matched = match_obj.group() # "fish"
# Note, if no match, match_obj is None
Run Code Online (Sandbox Code Playgroud)
更新: 将单词组合成单个替代单词模式时应该小心.以下代码构建一个正则表达式,但是转义任何正则表达式特殊字符并对单词进行排序,以便较长的单词在相同单词的任何较短前缀之前有机会匹配:
def wordlist_to_regex(words):
escaped = map(re.escape, words)
combined = '|'.join(sorted(escaped, key=len, reverse=True))
return re.compile(combined)
>>> r.search('smash atomic particles').span()
(6, 10)
>>> r.search('visit usenet:comp.lang.python today').span()
(13, 29)
>>> r.search('a north\south division').span()
(2, 13)
>>> r.search('012cat').span()
(3, 6)
>>> r.search('0123dog789cat').span()
(4, 7)
Run Code Online (Sandbox Code Playgroud)
结束更新
应该注意的是,您将希望尽可能少地形成正则表达式(即 - 调用re.compile()).最好的情况是你提前知道你的搜索是什么(或者你曾经/不经常计算它们),然后在某处保存re.compile的结果.我的例子只是一个简单的无意义函数,所以你可以看到正则表达式的用法.这里有一些更多的正则表达式文档:
http://docs.python.org/library/re.html
希望这可以帮助.
更新:我不确定python如何实现正则表达式,但回答Rax关于re.compile()是否有限制的问题(例如,你可以尝试"|"一起匹配多少个单词) ,以及运行编译的时间:这些似乎都不是问题.我试用了这段代码,这足以说服我.(我本可以通过添加时间和报告结果,以及将单词列表放入集合以确保没有重复...来改善这一点......但这两种改进看起来都有点过分.这段代码基本上是瞬间完成的,并且让我确信我能够搜索2000个单词(大小为10),并且这些单词将适当地匹配.这是代码:
import random
import re
import string
import sys
def main(args):
words = []
letters_and_digits = "%s%s" % (string.letters, string.digits)
for i in range(2000):
chars = []
for j in range(10):
chars.append(random.choice(letters_and_digits))
words.append(("%s"*10) % tuple(chars))
search_for = re.compile("|".join(words))
first, middle, last = words[0], words[len(words) / 2], words[-1]
search_string = "%s, %s, %s" % (last, middle, first)
match_obj = search_for.search(search_string)
if match_obj is None:
print "Ahhhg"
return
index = match_obj.start()
which = match_obj.group()
if index != 0:
print "ahhhg"
return
if words[-1] != which:
print "ahhg"
return
print "success!!! Generated 2000 random words, compiled re, and was able to perform matches."
if __name__ == "__main__":
main(sys.argv)
Run Code Online (Sandbox Code Playgroud)
更新:应该注意的是,在正则表达式中ORed在一起的事物的顺序很重要.看看 TZOTZIOY启发的以下测试:
>>> search_str = "01catdog"
>>> test1 = re.compile("cat|catdog")
>>> match1 = test1.search(search_str)
>>> match1.group()
'cat'
>>> match1.start()
2
>>> test2 = re.compile("catdog|cat") # reverse order
>>> match2 = test2.search(search_str)
>>> match2.group()
'catdog'
>>> match2.start()
2
Run Code Online (Sandbox Code Playgroud)
这表明订单很重要: - /.我不确定这对Rax的应用意味着什么,但至少这种行为是已知的.
更新:我发布了关于Python中正则表达式实现的这些问题,希望能够让我们深入了解这个问题所发现的问题.