【问题标题】:Python: Is there a shortcut to finding which substring(from a set of substrings) comes first in a string?Python:是否有快捷方式来查找字符串中的哪个子字符串(来自一组子字符串)?
【发布时间】:2016-08-14 10:32:43
【问题描述】:

假设我有一个字符串:

s = "Hello, stack exchange. Let's solve my query"

假设我有 3 个子字符串

s1 = "solve"
s2 = "stack"
s3 = "Not present"

是否有快捷方式来确定 s 中哪个子字符串先出现?

我知道,我可以编写一个函数来查找 substrs 的索引,可能将 substr-index 对存储在字典中,然后比较所有非负索引,但是有更短的方法或 pythonic 的方法吗?

【问题讨论】:

    标签: python string algorithm substring


    【解决方案1】:

    您可以使用生成器查找所有位置,并使用min() 查找最左侧的位置:

    positions = (s.find(sub), sub) for sub in (s1, s2, s3))
    leftmost = min((pos, sub) for pos, sub in positions if pos > -1)[1]
    

    这对每个子字符串只运行一次s.find(),过滤掉任何不存在的子字符串。如果根本没有匹配的子字符串,min() 将抛出 ValueError 异常;你可能想抓住它。

    这确实会扫描字符串 3 次;如果测试的子字符串的数量足够大,您可能希望构建一个 trie structure,将索引循环到 s 并测试该位置的字符是否存在于 trie 中:

    def make_trie(*words):
         root = {}
         for word in words:
             current = root
             for letter in word:
                 current = current.setdefault(letter, {})
             # insert sentinel at the end
             current[None] = None
         return root
    
    def find_first(s, trie):
        for i in range(len(s)):
            pos, current, found = i, trie, []
            while pos < len(s) and s[pos] in current:
                found.append(s[pos])
                current = current[s[pos]]
                if None in current:  # whole substring detected
                    return ''.join(found)
                pos += 1
    
    leftmost = find_first(s, make_trie(s1, s2, s3))
    

    trie 可以重复用于多个字符串。

    【讨论】:

      【解决方案2】:

      另一种使用正则表达式的方法是:

      import re
      s = "Hello, stack exchange. Let's solve my query"
      s1 = "solve"
      s2 = "stack"
      s3 = "Not present"
      r1 = re.compile('|'.join([s1,s2,s3]))
      r1.findall(s)
      

      这将返回一个这样的列表:

      ['stack', 'solve']
      

      从列表的索引中你可以得到哪个搜索字符串首先出现。

      【讨论】:

      • 您可以改用.finditer() 并且只生成第一个匹配项。
      【解决方案3】:

      这是执行此操作的最短方法。 创建一个正则表达式,并使用 re.search 在第一次匹配时中断。

      import re
      inputs = ['solve','stack','Not present']
      s = "Hello, stack exchange. Let's solve my query"
      match = re.search(re.compile('|'.join(inputs)),s)
      print(match.group())
      #returns 'stack'
      

      演示:http://codepad.org/qoFtkQys

      【讨论】:

      • OP 想要最左边的子字符串。不是那场比赛的位置。
      【解决方案4】:

      你可以试试这个:

      first_substr = min([(s.find(substr),substr) for substr in [s1, s2, s3] if s.find(substr)!=-1])[1]
      

      谢谢

      【讨论】:

      • 这和我的一样,但是s.find() 为每个子字符串调用了两次。你实现了整个列表对象first,我的生成器选项不需要这样做。
      猜你喜欢
      • 2015-03-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-05-11
      • 1970-01-01
      相关资源
      最近更新 更多