【问题标题】:Get all possible strings between 2 substrings in Python获取Python中2个子字符串之间的所有可能字符串
【发布时间】:2020-12-16 15:35:15
【问题描述】:

之前获取中间字符串has been asked但不涵盖某些条件的问题。就我而言,我可能有如下字符串:

subject = '"lorem ipsum", "foo", "baz", "bar", "lorem ipsum", "bar", "ipsum", "foo", "baz", "bar"'

我想提取foo", "", "bar" 之间的所有文本实例。传统的“介于两者之间”的答案是:

import re
result = re.findall('foo", "(.*)", "bar', subject)
print(result)

只返回 1 个结果字符串:

'baz", "bar", "lorem ipsum", "bar", "ipsum", "foo", "baz'

但我想要返回的是所有可能的“Between”字符串的列表,例如:

[
    'baz',
    'baz", "bar", "lorem ipsum',
    'baz", "bar", "lorem ipsum", "bar", "ipsum", "foo", "baz',
    'baz'
]

所以给定两个子字符串(开始和结束)和一个主题字符串,我怎样才能在subject 中获得startend 之间的所有可能子字符串?计算效率最高的解决方案当然是可取的。

【问题讨论】:

  • 您希望字符串有多长以及“中间”字符串有多少?
  • 对于我现在正在做的项目,不是很多(可能是 4-10 个)。当然,我们可以想象更大/任意的理论扩展要求。

标签: python python-3.x regex string


【解决方案1】:

您可以使用this one 之类的解决方案,您只需稍微修改一下即可满足您的正则表达式要求:

import re

def findall_overlapped(r, s):
  res = []                     # Resulting list
  reg = r'^{}$'.format(r)      # Regex must match full string
  for q in range(len(s)):      # Iterate over all chars in a string
    for w in range(q,len(s)):  # Iterate over the rest of the chars to the right
        cur = s[q:w+1]         # Currently tested slice
        m = re.match(reg, cur) # If there is a full slice match
        if m:
            res.append(m.group(1))    # Append Group 1 value to the resulting list
  return res

rx = r'foo", "(.*?)", "bar"'
text = '"lorem ipsum", "foo", "baz", "bar", "lorem ipsum", "bar", "ipsum", "foo", "baz", "bar"'
for s in findall_overlapped(rx, text):
    print(s)

Python code demo 的输出:

baz
baz", "bar", "lorem ipsum
baz", "bar", "lorem ipsum", "bar", "ipsum", "foo", "baz
baz

【讨论】:

    【解决方案2】:

    这是获得正确答案的一种方法。它搜索第一个词条,并为每个条目搜索列表的其余部分以查找第二个词条。

    subject = ["lorem ipsum", "foo", "baz", "bar", "lorem ipsum", "bar", "ipsum", "foo", "baz", "bar"]
    
    sch1 = "foo"
    sch2 = "bar"
    
    all = []
    
    for i1 in  range(len(subject)):  # search first term
       if subject[i1] == sch1: # found first term
           for i2 in range(i1, len(subject)):  # search second term
               if subject[i2] == sch2:   # found second term
                   all.extend(subject[i1+1:i2])  # add to main list
    
    print(all)
    

    输出(格式化)

    ['baz', 
     'baz', 'bar', 'lorem ipsum', 
     'baz', 'bar', 'lorem ipsum', 'bar', 'ipsum', 'foo', 'baz', 
     'baz']
    

    【讨论】:

      【解决方案3】:

      这是一种可行的方法,我会说相当有效。

      • 使用re.finditer,查找开始和结束模式的索引/跨度
      • 创建索引/跨度的所有合理组合
      • 切出结果
      subject = '"lorem ipsum", "foo", "baz", "bar", "lorem ipsum", "bar", "ipsum", "foo", "baz", "bar"'
      
      import re
      # spans of "start" pattern
      sSpans = [match.span() for match in re.finditer('foo", "' ,subject)]
      # spans of "end"   pattern
      eSpans = [match.span() for match in re.finditer('", "bar"',subject)]
      # all possible combination of "between" spans
      spans = [(s[1],e[0]) for s in sSpans for e in eSpans] 
      # filter only reasonable spand where end > start
      spans = [(s,e) for s,e in spans if e > s]
      # slice out the "between strings"
      result = [subject[s:e] for s,e in spans]
      for r in result: print(r)
      

      也可以压缩成一行:

      result = [subject[s.span()[1]:e.span()[0]] for s in re.finditer('foo", "' ,subject) for e in re.finditer('", "bar"',subject) if e.span()[0] > s.span()[1]]
      for r in result: print(r)
      

      【讨论】:

        【解决方案4】:

        可能不是最快的解决方案:

        from timeit import default_timer as timer                                                                                                                                                                
        
        subject = '"lorem ipsum", "foo", "baz", "bar", "lorem ipsum", "bar", "ipsum",     "foo", "baz", "bar"'
        
        key1 = 'foo", "'
        key2 = '", "bar"'
        
        t_start = timer()
        
        keyl1 = []
        keyl2 = []
        result = []
        
        start = 0 
        start2 = 0
        end = len(subject)
        
        while True:
            keyl1.append(subject.find(key1,start,end))
            start = keyl1[-1]+1
            if keyl1[-1] == -1:
               break
           start2 = start
           while True:
               keyl2.append(subject.find(key2,start2,end))
               if keyl2[-1] == -1:
                   keyl2 = []
                   break
               if keyl2[-1]>keyl1[-1]:
                   result.append(subject[keyl1[-1]+len(key1):keyl2[-1]])
               start2 = keyl2[-1]+1
        
        for r in result:
            print(r)
        
        t_end = timer()
        print('Seconds: ', t_end - t_start)
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-02-09
          • 2015-06-24
          • 2015-02-18
          • 1970-01-01
          • 2014-03-31
          • 1970-01-01
          相关资源
          最近更新 更多