【问题标题】:Search for any number of unknown substrings in place of * in a list of string在字符串列表中搜索任意数量的未知子字符串来代替 *
【发布时间】:2017-03-29 14:10:51
【问题描述】:

首先,对不起,如果标题不是很明确,我很难正确地表述它。这也是为什么我没有找到问题是否已经被问过,如果有的话。

所以,我有一个字符串列表,我想执行“程序”搜索,用任何可能的子字符串替换我的目标子字符串中的每个 *
这是一个例子:

strList = ['obj_1_mesh',
           'obj_2_mesh',
           'obj_TMP',
           'mesh_1_TMP',
           'mesh_2_TMP',
           'meshTMP']

searchFor('mesh_*')
# should return: ['mesh_1_TMP', 'mesh_2_TMP']

在这种只有一个* 的情况下,我只需用* 拆分每个字符串并使用startswith() 和/或endswith(),这样就可以了。 但是如果搜索字符串中有多个*,我不知道该怎么做。

所以我的问题是,如何在字符串列表中搜索任意数量的未知子字符串来代替 *
例如:

strList = ['obj_1_mesh',
           'obj_2_mesh',
           'obj_TMP',
           'mesh_1_TMP',
           'mesh_2_TMP',
           'meshTMP']

searchFor('*_1_*')
# should return: ['obj_1_mesh', 'mesh_1_TMP']

希望一切都足够清楚。谢谢。

【问题讨论】:

  • 您可能想查看re 的正则表达式。
  • 解释你如何到达['mesh_ok1', 'mesh_ok2'] 作为第一个示例的预期输出。
  • 哦,是的,抱歉,那是因为我修改了示例代码而没有更改结果。我现在编辑它。

标签: python string search


【解决方案1】:

考虑使用提供类 Unix 文件模式匹配的“fnmatch”。更多信息在这里http://docs.python.org/2/library/fnmatch.html

from fnmatch import fnmatch
strList = ['obj_1_mesh',
       'obj_2_mesh',
       'obj_TMP',
       'mesh_1_TMP',
       'mesh_2_TMP',
       'meshTMP']

searchFor = '*_1_*'

resultSubList = [ strList[i] for i,x in enumerate(strList) if fnmatch(x,searchFor) ]

这应该可以解决问题

【讨论】:

  • 如果您提供指向 fnmatch 文档的链接,并且还简要解释了 fnmatch 的作用,这个答案会更好一些。只需说“fnmatch 提供了匹配类似于 unix 文件名通配符的模式的能力”之类的内容,您就可以将其从一个好的答案变成一个好的答案。
【解决方案2】:

如果我是你,我会为此使用正则表达式包。您必须学习一点正则表达式才能进行正确的搜索查询,但这还不错。在这种情况下,“.+”与“*”非常相似。

import re

def search_strings(str_list, search_query):
    regex = re.compile(search_query)
    result = []
    for string in str_list:
        match = regex.match(string)
        if match is not None:
            result+=[match.group()]
    return result

strList= ['obj_1_mesh',
          'obj_2_mesh',
          'obj_TMP',
          'mesh_1_TMP',
          'mesh_2_TMP',
          'meshTMP']

print search_strings(strList, '.+_1_.+')

这应该返回 ['obj_1_mesh', 'mesh_1_TMP']。我试图复制 '*_1_*' 案例。对于“mesh_*”,您可以将 search_query 设为“mesh_.+”。这是python regex api的链接:https://docs.python.org/2/library/re.html

【讨论】:

  • 在这里使用非贪婪匹配可能是个好主意。
  • 是的,这取决于 OP。我使用了贪婪,因为我认为在这种特殊情况下直觉上更有意义。 OP 如果你想要非贪婪使用 '*' 而不是 '+'。
  • 谢谢!所有的答案都很好,但是由于这个答案不那么简洁,所以我更容易理解它(因为我没有使用太多的正则表达式并且现在还没有完全理解它)。我还按照建议更改了“*”中的“+”,我认为这样更精确。
  • 嘿,再解释一下,点匹配任何字符,然后 * 表示匹配前一个模式的 0 个或多个。 + 表示匹配 1 或更多。举个例子,'.+_1_.+' 不会匹配 '_1_TMP',但 '.*_1_.*' 会。
  • 是的,这就是我通过测试得出的结论。再次感谢:)
【解决方案3】:

最简单的方法是使用fnmatch,如ma3oun 的回答所示。但这里有一种使用Regular Expressions 的方法,也就是正则表达式。

首先我们转换您的searchFor 模式,使其使用'.+?' 作为“通配符”而不是'*'。然后我们将结果编译成一个正则表达式模式对象,以便我们可以有效地使用它进行多次测试。

有关正则表达式语法的解释,请参阅文档。但简而言之,点表示任何字符(在这一行),+ 表示查找其中一个或多个,? 表示进行非贪婪匹配,即匹配符合模式的最小字符串而不是最长的,(这是贪心匹配所做的)。

import re

strList = ['obj_1_mesh',
           'obj_2_mesh',
           'obj_TMP',
           'mesh_1_TMP',
           'mesh_2_TMP',
           'meshTMP']

searchFor = '*_1_*'
pat = re.compile(searchFor.replace('*', '.+?'))

result = [s for s in strList if pat.match(s)]
print(result)

输出

['obj_1_mesh', 'mesh_1_TMP']

如果我们使用searchFor = 'mesh_*',结果是

['mesh_1_TMP', 'mesh_2_TMP']

请注意,此解决方案稳健。如果searchFor 包含在正则表达式中具有特殊含义的其他字符,则它们需要是escaped。实际上,与其进行searchFor.replace 转换,不如一开始就使用正则表达式语法编写模式会更简洁。

【讨论】:

    【解决方案4】:

    如果您要查找的字符串总是看起来像 string,您可以使用 find 函数,您会得到类似的结果:

    for s in strList:
        if s.find(searchFor) != -1:
            do_something()
    

    如果您要查找多个字符串(例如 abc*123*test),则需要查找每个字符串,从找到第一个的索引开始在同一字符串中找到第二个 + 它是 len等等。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-12-24
      • 1970-01-01
      • 2014-08-30
      • 2017-12-01
      • 1970-01-01
      • 2013-04-11
      • 2016-04-21
      • 2019-08-26
      相关资源
      最近更新 更多