【问题标题】:How can I find the position of the list of substrings from the string?如何从字符串中找到子字符串列表的位置?
【发布时间】:2017-10-02 02:33:34
【问题描述】:

如何从字符串中找到子串列表的位置?

给定一个字符串:

“周六,这架飞往圣彼得堡的飞机在从沙姆沙伊赫起飞 23 分钟后,在埃及的西奈沙漠坠毁。”

还有一个子串列表:

['The', 'plane', ',', 'bound', 'for', 'St', 'Petersburg', ',', 'crashed', 'in', 'Egypt', "' s”、“西奈”、“沙漠”、“刚刚”、“23”、“分钟”、“之后”、“起飞”、“从”、“沙姆”、“沙伊赫”、“开” , '星期六', '.']

期望的输出:

>>> s = "The plane, bound for St Petersburg, crashed in Egypt's Sinai desert just 23 minutes after take-off from Sharm el-Sheikh on Saturday."
>>> tokens = ['The', 'plane', ',', 'bound', 'for', 'St', 'Petersburg', ',', 'crashed', 'in', 'Egypt', "'s", 'Sinai', 'desert', 'just', '23', 'minutes', 'after', 'take-off', 'from', 'Sharm', 'el-Sheikh', 'on', 'Saturday', '.']
>>> find_offsets(tokens, s)
[(0, 3), (4, 9), (9, 10), (11, 16), (17, 20), (21, 23), (24, 34),
        (34, 35), (36, 43), (44, 46), (47, 52), (52, 54), (55, 60), (61, 67),
        (68, 72), (73, 75), (76, 83), (84, 89), (90, 98), (99, 103), (104, 109),
        (110, 119), (120, 122), (123, 131), (131, 132)]

输出说明,第一个子字符串“The”可以通过使用字符串s 使用(start, end) 索引找到。所以从所需的输出。

因此,如果我们从所需输出中遍历所有整数元组,我们将得到子字符串列表,即

>>> [s[start:end] for start, end in out]
['The', 'plane', ',', 'bound', 'for', 'St', 'Petersburg', ',', 'crashed', 'in', 'Egypt', "'s", 'Sinai', 'desert', 'just', '23', 'minutes', 'after', 'take-off', 'from', 'Sharm', 'el-Sheikh', 'on', 'Saturday', '.']

我试过了:

def find_offset(tokens, s):
    index = 0
    offsets = []
    for token in tokens:
        start = s[index:].index(token) + index
        index = start + len(token)
        offsets.append((start, index))
    return offsets

还有其他方法可以从字符串中找到子字符串列表的位置吗?

【问题讨论】:

    标签: python string indexing substring offset


    【解决方案1】:
    import re
    
    s = "The plane, bound for St Petersburg, crashed in Egypt's Sinai desert just 23 minutes after take-off from Sharm el-Sheikh on Saturday."
    tokens = ['The', 'plane', ',', 'bound', 'for', 'St', 'Petersburg', ',', 'crashed', 'in', 'Egypt', "'s", 'Sinai', 'desert', 'just', '23', 'minutes', 'after', 'take-off', 'from', 'Sharm', 'el-Sheikh', 'on', 'Saturday', '.']
    
    
    for token in tokens:
      pattern = re.compile(re.escape(token))
      print(pattern.search(s).span())
    

    结果

    (0, 3)
    (4, 9)
    (9, 10)
    (11, 16)
    (17, 20)
    (21, 23)
    (24, 34)
    (9, 10)
    (36, 43)
    (44, 46)
    (47, 52)
    (52, 54)
    (55, 60)
    (61, 67)
    (68, 72)
    (73, 75)
    (76, 83)
    (84, 89)
    (90, 98)
    (99, 103)
    (104, 109)
    (110, 119)
    (120, 122)
    (123, 131)
    (131, 132)
    

    【讨论】:

      【解决方案2】:

      第一个解决方案:

      #use list comprehension and list.index function.
      [tuple((s.index(e),s.index(e)+len(e))) for e in t]
      

      解决第一个解决方案中的问题的第二个解决方案:

      def find_offsets(tokens, s):
          tid = [list(e) for e in tokens]
          i = 0
          for id_token,token in enumerate(tid):
              while (token[0]!=s[i]):            
                  i+=1
              tid[id_token] = tuple((i,i+len(token)))
              i+=len(token)
      
          return tid
      
      
      find_offsets(tokens, s)
      Out[201]: 
      [(0, 3),
       (4, 9),
       (9, 10),
       (11, 16),
       (17, 20),
       (21, 23),
       (24, 34),
       (34, 35),
       (36, 43),
       (44, 46),
       (47, 52),
       (52, 54),
       (55, 60),
       (61, 67),
       (68, 72),
       (73, 75),
       (76, 83),
       (84, 89),
       (90, 98),
       (99, 103),
       (104, 109),
       (110, 119),
       (120, 122),
       (123, 131),
       (131, 132)]   
      
      #another test
      s = 'The plane, plane'
      t = ['The', 'plane', ',', 'plane']
      find_offsets(t,s)
      Out[212]: [(0, 3), (4, 9), (9, 10), (11, 16)]
      

      【讨论】:

      • 非常简短,但也非常低效,两次调用.index()
      • 另外,如果有重复的单词,这将不起作用。 .index() 总是只获取第一个实例 =(
      • 试试s = 'The plane, plane'; t = ['The', 'plane', ',', 'plane']
      【解决方案3】:

      如果我们对子字符串一无所知,除了为每个子字符串重新扫描整个文本之外,别无他法。

      如果从数据看来,我们知道这些是文本的连续片段,按文本顺序给出,那么在每次匹配后只扫描文本的 其余部分 是很容易的。不过,每次都剪掉文本是没有意义的。

      def spans(text, fragments):
          result = []
          point = 0  # Where we're in the text.
          for fragment in fragments:
              found_start = text.index(fragment, point)
              found_end = found_start + len(fragment)
              result.append((found_start, found_end))
              point = found_end
          return result
      

      测试:

      >>> spans('foo in bar', ['foo', 'in', 'bar'])
      [(0, 3), (4, 6), (7, 10)]
      

      这假设每个片段都出现在文本中的正确位置。您的输出格式未提供不匹配报告的示例。使用 .find 而不是 .index 可能会有所帮助,尽管只是部分。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-05-21
        • 1970-01-01
        • 2014-05-06
        • 2021-04-21
        • 2018-11-24
        • 1970-01-01
        • 2016-10-21
        相关资源
        最近更新 更多