Python:匹配字符串中的多个子字符串

我正在使用 Python,我想将给定的字符串与多个子字符串匹配。我试图以两种不同的方式解决这个问题。我的第一个解决方案是将子字符串与如下字符串匹配:


str = "This is a test string from which I want to match multiple substrings"

value = ["test", "match", "multiple", "ring"]

temp = []

temp.extend([x.upper() for x in value if x.lower() in str.lower()])

print(temp)

这导致 temp = ["TEST", "MATCH", "MULTIPLE", "RING"]


然而,这不是我想要的结果。子串应该完全匹配,所以“ring”不应该与“string”匹配。


这就是为什么我试图用正则表达式解决这个问题,像这样:


str = "This is a test string from which I want to match multiple substrings"

value = ["test", "match", "multiple", "ring"]

temp = []

temp.extend([x.upper() for x in value if regex.search(r"\b" + regex.escape(x) + r"\b", str,

                                                   regex.IGNORECASE) is not None])

print(temp)

这导致 ["TEST", "MATCH", "MULTIPLE"],正确的解决方案。尽管如此,该解决方案的计算时间太长。我必须对大约 100 万个字符串进行此检查,与使用第一个解决方案所需的 1.5 小时相比,使用正则表达式的解决方案需要数天才能完成。


我想知道是否有办法使第一个解决方案起作用,或者使第二个解决方案运行得更快。提前致谢


编辑:value也可以包含数字,或者像“test1 test2”这样的短语


HUH函数
浏览 231回答 3
3回答

慕森卡

在不查看实际数据的情况下很难提出最佳解决方案,但您可以尝试以下方法:生成匹配所有值的单个模式。这样您只需要搜索字符串一次(而不是每个值一次)。跳过转义值,除非它们包含特殊字符(如'^'或'*')。将结果直接分配给temp,避免使用 进行不必要的复制temp.extend()。import regex# 'str' is a built-in name, so use 'string' insteadstring = 'This is a Test string from which I want to match multiple substrings'values = ['test', 'test2', 'Multiple', 'ring', 'match']pattern = r'\b({})\b'.format('|'.join(map(regex.escape, values)))# unique matches, lowercasedmatches = set(map(str.lower, regex.findall(pattern, string, regex.IGNORECASE)))# arrange the results as they appear in `values`temp = [x.upper() for x in values if x.lower() in matches]print(temp)  # ['TEST', 'MULTIPLE', 'MATCH']

吃鸡游戏

想到了两种可能的优化:预编译模式,re.compile所以它不会在每次调用时重新编译match。与其匹配四个独立的正则表达式,不如创建一个匹配所有值的正则表达式。import restr = "This is a test string from which I want to match test1 test2 multiple substrings"values = ["test", "match", "multiple", "ring", "test1 test2"]pattern = re.compile("|".join(r"\b" + re.escape(x) + r"\b" for x in values))temp = []temp.extend([x.upper() for x in pattern.findall(str, re.IGNORECASE)])print(temp)结果:['TEST', 'MATCH', 'TEST1 TEST2', 'MULTIPLE']这种方法的潜在缺点:输出的顺序可能不同。您的原始方法将结果按它们在 中出现的顺序排列values。这种方法将结果按它们出现的顺序排列str。temp如果在 中出现多次,相同的值将出现多次str。与您的原始方法相反,该值在temp.search一旦找到匹配就终止。findall总是搜索整个字符串。如果您希望大多数字符串匹配 中的每个单词value,并且希望大多数匹配出现在字符串的早期,那么findall可能比search. 另一方面,如果您希望搜索经常出现None,那么findall速度可能会更快一些。

慕姐4208626

您可以str按空间拆分,然后将元素value与==编辑:所以你说一些字符串在values它们之前或之后可以有空格。你可以用这一行解决这个问题:values = [i.strip() for i in values]这将删除字符串前后的所有空白字符(在您的情况下,每个元素)。此外,您提到如果str按空格拆分,某些单词'Hi, how are you?'会因拆分而留下标点符号 ->将导致['Hi,', 'how', 'are', 'you?']. 您可以通过使用字符串startswith()内置方法过滤所有以元素开头的单词来解决此问题,values如下所示:str = ['Hi,', 'how', 'are', 'you?']`values = ['how', 'you', 'time', 'space']new_str = []for word in str:  for j in values:    if word.startswith(j):      new_str.append(word)# result -> ['how', 'you?']然后你可以用一些正则表达式从结果列表中删除标点符号,但现在你将有一个更小的列表来迭代。删除所有标点符号后,您可以按照我在原始答案中的建议匹配整个字符串。我希望现在更清楚了。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Python