在不多次迭代的情况下在字符串中查找多个子字符串
Finding multiple substrings in a string without iterating over it multiple times
我需要查找列表中的项目是否出现在字符串中,然后将这些项目添加到不同的列表中。此代码有效:
data =[]
line = 'akhgvfalfhda.dhgfa.lidhfalihflaih**Thing1**aoufgyafkugafkjhafkjhflahfklh**Thing2**dlfkhalfhafli...'
_legal = ['thing1', 'thing2', 'thing3', 'thing4',...]
for i in _legal:
if i in line:
data.append(i)
但是,代码迭代 line
(可能很长)多次 - 与 _legal
中的项目(可能是 lot).这对我来说太慢了,我正在寻找一种更快的方法。 line
没有任何特定的格式,所以据我所知,使用 .split()
是行不通的。
编辑:更改 line
以便更好地代表问题。
一种方法是构建一个非常简单的正则表达式模式,并使用 re.findall()
到 find/extract 字符串中任何匹配的词。
import re
line = 'akhgvfalfhda.dhgfa.lidhfalihflaih**Thing1**aoufgyafkugafkjhafkjhflahfklh**Thing2**dlfkhalfhafli...'
_legal = ['thing1', 'thing2', 'thing3', 'thing4']
exp = re.compile(r'|'.join(_legal), re.IGNORECASE)
exp.findall(line)
>>> ['Thing1', 'Thing2']
我能想到的一种改进方法是:
- 获取
_legal
中单词的所有唯一长度
- 使用滑动 window 技术从这些特定长度的
line
构建单词词典。复杂度应该是O( len(line)*num_of_unique_lengths )
,这应该比蛮力好。
- 现在在 O(1) 的字典中查找每个
thing
。
代码:
line = 'thing1 thing2 456 xxualt542l lthin. dfjladjfj lauthina '
_legal = ['thing1', 'thing2', 'thing3', 'thing4', 't5', '5', 'fj la']
ul = {len(i) for i in _legal}
s=set()
for l in ul:
s = s.union({line[i:i+l] for i in range(len(line)-l)})
print(s.intersection(set(_legal)))
输出:
{'thing1', 'fj la', 'thing2', 't5', '5'}
以下内容应该非常有效。它实现了
的建议
lens=set([len(i) for i in _legal])
d={}
for k in lens:
d[k]=[line[i:i+k] for i in range(len(line)-k)]
s=set(sum(d.values(), []))
result=list(s.intersection(set(_legal)))
对于以下数据(由于 Thing1 和 Thing2 中的大写字母,它返回一个空列表,我稍微更改了“行”)
line = 'akhgvfalfhda.dhgfa.lidhfalihflaih**thing1**aoufgyafkugafkjhafkjhflahfklh**thing2**dlfkhalfhafli...'
_legal = ['thing1', 'thing2', 'thing3', 'thing4',...]
输出为:
print(result)
['thing2', 'thing1']
说明:
我们将所有可能的单词长度保存在子字符串中。对于这些长度,我们在文本中创建了所有可能的子串(集合 s)。终于找到了s和子串中的common item,这就是问题的答案
我需要查找列表中的项目是否出现在字符串中,然后将这些项目添加到不同的列表中。此代码有效:
data =[]
line = 'akhgvfalfhda.dhgfa.lidhfalihflaih**Thing1**aoufgyafkugafkjhafkjhflahfklh**Thing2**dlfkhalfhafli...'
_legal = ['thing1', 'thing2', 'thing3', 'thing4',...]
for i in _legal:
if i in line:
data.append(i)
但是,代码迭代 line
(可能很长)多次 - 与 _legal
中的项目(可能是 lot).这对我来说太慢了,我正在寻找一种更快的方法。 line
没有任何特定的格式,所以据我所知,使用 .split()
是行不通的。
编辑:更改 line
以便更好地代表问题。
一种方法是构建一个非常简单的正则表达式模式,并使用 re.findall()
到 find/extract 字符串中任何匹配的词。
import re
line = 'akhgvfalfhda.dhgfa.lidhfalihflaih**Thing1**aoufgyafkugafkjhafkjhflahfklh**Thing2**dlfkhalfhafli...'
_legal = ['thing1', 'thing2', 'thing3', 'thing4']
exp = re.compile(r'|'.join(_legal), re.IGNORECASE)
exp.findall(line)
>>> ['Thing1', 'Thing2']
我能想到的一种改进方法是:
- 获取
_legal
中单词的所有唯一长度
- 使用滑动 window 技术从这些特定长度的
line
构建单词词典。复杂度应该是O( len(line)*num_of_unique_lengths )
,这应该比蛮力好。 - 现在在 O(1) 的字典中查找每个
thing
。
代码:
line = 'thing1 thing2 456 xxualt542l lthin. dfjladjfj lauthina '
_legal = ['thing1', 'thing2', 'thing3', 'thing4', 't5', '5', 'fj la']
ul = {len(i) for i in _legal}
s=set()
for l in ul:
s = s.union({line[i:i+l] for i in range(len(line)-l)})
print(s.intersection(set(_legal)))
输出:
{'thing1', 'fj la', 'thing2', 't5', '5'}
以下内容应该非常有效。它实现了
lens=set([len(i) for i in _legal])
d={}
for k in lens:
d[k]=[line[i:i+k] for i in range(len(line)-k)]
s=set(sum(d.values(), []))
result=list(s.intersection(set(_legal)))
对于以下数据(由于 Thing1 和 Thing2 中的大写字母,它返回一个空列表,我稍微更改了“行”)
line = 'akhgvfalfhda.dhgfa.lidhfalihflaih**thing1**aoufgyafkugafkjhafkjhflahfklh**thing2**dlfkhalfhafli...'
_legal = ['thing1', 'thing2', 'thing3', 'thing4',...]
输出为:
print(result)
['thing2', 'thing1']
说明: 我们将所有可能的单词长度保存在子字符串中。对于这些长度,我们在文本中创建了所有可能的子串(集合 s)。终于找到了s和子串中的common item,这就是问题的答案