【问题标题】:Check if a string contains all words of another string in the same order python?检查一个字符串是否包含以相同顺序python的另一个字符串的所有单词?
【发布时间】:2017-01-08 16:23:51
【问题描述】:

我想检查一个字符串是否包含所有子字符串的单词并保留它们的顺序;目前我正在使用以下代码;然而,它非常基本,似乎效率低下,并且可能有更好的方法来做到这一点。如果您能告诉我更有效的解决方案是什么,我将不胜感激。抱歉有一个菜鸟问题,我是编程新手,无法找到好的解决方案

def check(main, sub_split):
    n=0
    while n < len(sub_split):
        result = True
        if sub_split[n] in main:
            the_start =  main.find(sub_split[n])
            main = main[the_start:]

        else:
            result=False
        n += 1
    return result

a = "I believe that the biggest castle in the world is Prague Castle "
b= "the biggest castle".split(' ')

print check(a, b)

更新:有趣;首先感谢大家的回答。还要感谢您指出我的代码遗漏的一些地方。我一直在尝试此处和链接中发布的不同解决方案,我将添加更新他们如何比较并接受答案。

更新: 再次感谢大家提供的出色解决方案,与我的代码相比,每个解决方案都有重大改进;我用我对 100000 检查的要求检查了建议,得到了以下结果; 建议: Padraic Cunningham - 始终低于 0.4 秒(尽管在仅搜索完整单词时会出现一些误报; 银河系 - 0.65 秒; 0.75 秒 友好的狗 - 0.70 秒 John1024 - 1.3 秒(高度准确,但似乎需要额外的时间)

【问题讨论】:

  • 您只需要all :))) print all(x in a for x in b)
  • 如果你也将main拆分成一个列表,你可以使用apply this回答。
  • @alfasin all 似乎都返回 True 即使单词的顺序不同;例如 a = "我的城堡相信世界上最大的城堡是布拉格城堡" b = "最大的城堡".split(' ') 返回为 True,虽然它应该是 false
  • alfasin 的代码应为it = iter(a); print all(x in it for x in b) 以说明订单。请参阅我之前链接的Q/A
  • @Copperfield 只会检查b 是否是a子字符串,而不是子序列b 中的单词不必在a 中连续出现。

标签: python string python-2.7 substring


【解决方案1】:

如果你只是想检查一个单词是否包含在其他字符串中,不需要检查所有。您只需要找到一个并返回 true。
当您检查项目集时更快 O(1)(平均)

a = "I believe that the biggest castle in the world is Prague Castle "
b = "the biggest castle"

def check(a,b):
    setA,lstB = set( a.split() ), b.split() 
    if len(setA) < len(lstB): return False 
    for item in lstB:
        if item in setA:
            return True
    return False

print check(a,b)

如果你不在乎速度

def check(a,b):
    setA,lstB = set( a.split() ), b.split() 
    return len(setA) >= len(lstB) and any( 1 for item in lstB if item in setA) 

速度和时间复杂度:link

【讨论】:

    【解决方案2】:

    让我们定义您的 a 字符串并将您的 b 字符串重新格式化为正则表达式:

    >>> a = "I believe that the biggest castle in the world is Prague Castle "
    >>> b = r'\b' + r'\b.*\b'.join(re.escape(word) for word in "the biggest castle".split(' ')) + r'\b'
    

    这个测试看看b中的单词在a中出现的顺序是否相同:

    >>> import re
    >>> bool(re.search(b, a))
    True
    

    警告:如果速度很重要,非正则表达式方法可能更快。

    工作原理

    这里的关键是将字符串重新表述为正则表达式:

    >>> b = r'\b' + r'\b.*\b'.join(re.escape(word) for word in "the biggest castle".split(' ')) + r'\b'
    >>> print(b)
    \bthe\b.*\bbiggest\b.*\bcastle\b
    

    \b 仅匹配单词边界。这意味着,例如,单词the 永远不会与单词there 混淆。此外,此正则表达式要求所有单词以相同的顺序出现在目标字符串中。

    如果a 包含与正则表达式b 的匹配项,则re.search(b, a) 返回一个匹配对象。否则,它返回None。因此,bool(re.search(b, a)) 仅在找到匹配项时才返回 True

    标点符号示例

    由于单词边界将标点符号视为非单词字符,因此这种方法不会被标点符号混淆:

    >>> a = 'From here, I go there.'
    >>> b = 'here there'
    >>> b = r'\b' + r'\b.*\b'.join(re.escape(word) for word in b.split(' ')) + r'\b'
    >>> bool(re.search(b, a))
    True
    

    【讨论】:

    • 这是一个非常有趣的技巧。然而它并没有用,因为它的效率和可读性都比其他替代品低。
    • 我发现正则表达式非常清晰易读。另一方面,如果您发布了一个出色的答案,我会很乐意支持它。
    • 鉴于答案here 可能是正则表达式 的快速方法。
    【解决方案3】:

    您可以通过将上一个匹配项的索引 + 1 传递给 find 来简化搜索,您不需要对任何内容进行切片:

    def check(main, sub_split):
        ind = -1
        for word in sub_split:
            ind = main.find(word, ind+1)
            if ind == -1:
                return False
        return True
    
    a = "I believe that the biggest castle in the world is Prague Castle "
    b= "the biggest castle".split(' ')
    
    print check(a, b)
    

    如果 ind 曾经是 -1 那么你没有匹配到所以你返回 False,如果你把所有的词都弄透了,那么所有的词都按顺序在字符串中.

    对于确切的单词,您可以对列表执行类似的操作:

    def check(main, sub_split):
        lst, ind = main.split(), -1
        for word in sub_split:
            try:
               ind = lst.index(word, ind + 1)
            except ValueError:
                return False
        return True
    

    为了处理标点,你可以先把它去掉:

    from string import punctuation
    
    def check(main, sub_split):
        ind = -1
        lst = [w.strip(punctuation) for w in main.split()]
        for word in (w.strip(punctuation) for w sub_split):
            try:
               ind = lst.index(word, ind + 1)
            except ValueError:
                return False
        return True
    

    当然,有些词在标点符号下是有效的,但这更多的是 nltk 的工作,或者您可能实际上想要找到包括任何标点符号在内的匹配项。

    【讨论】:

    • @John1024, true 但由于 OP 使用的是 in 我假设子字符串可以匹配,如果不是,则可能需要带有单词边界的正则表达式或基于迭代器的方法.还有标点符号和大小写的情况,但 OP 似乎在他们自己的代码中没有这种情况,这可能是一个疏忽。
    • 你是对的:OP 使用的是in。在这种情况下,+1。
    • @John1024,在你的正则表达式和这个之间,他们应该得到他们需要的东西。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-03-13
    • 1970-01-01
    • 2023-03-31
    • 1970-01-01
    • 1970-01-01
    • 2014-04-21
    • 1970-01-01
    相关资源
    最近更新 更多