Python的:在一个字符串匹配多个子

问题描述 投票:1回答:3

我使用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)

这导致温度= [ “TEST”, “匹配”, “多”, “RING”]

然而,这是没有结果的,我想。该字符串应该有一个精确匹配,所以“环”不应该“字符串”匹配。

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

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”,“匹配”,“多重”],正确的解决方案。即使如此,因为它可能,这种解决方案需要很长时间来计算。我必须做这个检查为大约百万字符串和使用正则表达式将需要数天的解决方案来完成相比,1.5分,这需要使用的第一个解决方案。

我想知道是否有办法要么使第一个解决方案的工作,或者第二个解决方案,运行速度更快。提前致谢

编辑:value还可以包含数字,或像“测试1测试2”一个短语

python regex python-3.x string substring
3个回答
3
投票

很难提出最佳的解决方案,没有看到实际的数据,但你可以尝试这些东西:

  • 产生一个模式匹配所有的值。这样,你只需要(每个价值,而不是一次),一次搜索的字符串。
  • 跳过转义值,除非它们包含特殊字符(如'^''*')。
  • 直接把结果赋给temp,避免与temp.extend()不必要的复制。
import regex

# 'str' is a built-in name, so use 'string' instead
string = '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, lowercased
matches = 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']

2
投票

两种可能的优化浮现在脑海中:

  • 预编译的模式与re.compile所以它不会重新编译每次调用match时间。
  • 而不是针对四个独立的正则表达式匹配,建立一个满足你所有的值中的一个正则表达式。

import re

str = "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将可能有所加快。

0
投票

您可以通过空间分割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?']

然后,你可以从导致一些正则表达式列表中删除标点,但现在你将有很多小的列表遍历。在删除所有的标点字符,那么你可以为我在原来的答复建议匹配整个字符串。

我希望这是更清晰了。

© www.soinside.com 2019 - 2024. All rights reserved.