【问题标题】:Concatenate two strings with a common substring?用公共子字符串连接两个字符串?
【发布时间】:2017-10-21 07:07:43
【问题描述】:

假设我有字符串,

string1 = 'Hello how are you'
string2 = 'are you doing now?'

结果应该是这样的

Hello how are you doing now?

我正在考虑使用re 和字符串搜索的不同方式。 (Longest common substring problem)

但是在 python 中是否有任何简单的方法(或库)可以做到这一点?

为了清楚起见,我将再添加一组测试字符串!

string1 = 'This is a nice ACADEMY'
string2 = 'DEMY you know!'

结果会是!,

'This is a nice ACADEMY you know!'

【问题讨论】:

  • string1 = 'Hello how are you now?' 应该是什么结果? (now? 已添加)
  • 现在有你的问题了!实际情况并非如此。
  • 结果可以是'Hello how are you now are you doing now'。虽然这样的字符串不太可能出现!
  • 虽然如果结果是'Hello how are you doing now' 即使添加了now? 也会很棒
  • 现在?添加了 - 但now? 在这种情况下很常见

标签: python string


【解决方案1】:

应该这样做:

string1 = 'Hello how are you'
string2 = 'are you doing now?'
i = 0
while not string2.startswith(string1[i:]):
    i += 1

sFinal = string1[:i] + string2

输出:

>>> sFinal
'Hello how are you doing now?'

或者,把它变成一个函数,这样你就可以在不重写的情况下再次使用它:

def merge(s1, s2):
    i = 0
    while not s2.startswith(s1[i:]):
        i += 1
    return s1[:i] + s2

输出:

>>> merge('Hello how are you', 'are you doing now?')
'Hello how are you doing now?'
>>> merge("This is a nice ACADEMY", "DEMY you know!")
'This is a nice ACADEMY you know!'

【讨论】:

    【解决方案2】:

    这应该做你想做的:

    def overlap_concat(s1, s2):
        l = min(len(s1), len(s2))
        for i in range(l, 0, -1):
            if s1.endswith(s2[:i]):
                return s1 + s2[i:]
        return s1 + s2
    

    例子:

    >>> overlap_concat("Hello how are you", "are you doing now?")
    'Hello how are you doing now?'
    >>> 
    
    >>> overlap_concat("This is a nice ACADEMY", "DEMY you know!")
    'This is a nice ACADEMY you know!'
    >>> 
    

    【讨论】:

      【解决方案3】:

      使用str.endswithenumerate

      def overlap(string1, string2):
          for i, s in enumerate(string2, 1):
               if string1.endswith(string2[:i]):
                  break
      
          return string1 + string2[i:]
      
      >>> overlap("Hello how are you", "are you doing now?")
      'Hello how are you doing now?'
      
      >>> overlap("This is a nice ACADEMY", "DEMY you know!")
      'This is a nice ACADEMY you know!'
      

      如果您要考虑尾随特殊字符,您可能希望使用一些基于 re 的替换。

      import re
      string1 = re.sub('[^\w\s]', '', string1)
      

      虽然请注意,这会删除第一个字符串中的所有特殊字符。


      对上述函数的修改将找到最长的匹配子字符串(而不是最短的),涉及反向遍历string2

      def overlap(string1, string2):
         for i in range(len(s)):
            if string1.endswith(string2[:len(string2) - i]):
                break
      
         return string1 + string2[len(string2) - i:]
      
      >>> overlap('Where did', 'did you go?') 
      'Where did you go?'

      【讨论】:

      • @TomKarzes 说“它不起作用”有点过分,因为这可以通过在迭代前反转字符串来解决。我将把它留给 OP,因为他们从来没有指定任何类型的东西(实际上,OP 并不真正知道他们想要什么)。
      • 这不起作用。它找到最小的非空重叠,而不是最大的。例如,对于重叠('Where did','did you go?'),它给出'Where did you go?',而不是期望的'Where did you go?'。它需要从尽可能长的重叠开始,而不是最小的。
      • @TomKarzes 是的,我之前看过你的评论,请看我上面的回复。
      • 对不起,我删除了我原来的评论,并提供了一个更清晰的例子来说明这个版本是如何失败的。如果第一个字符串的最后一个字符与第二个字符串的第一个字符相同,它只会找到一个字符重叠。我认为这显然不是我们想要的。
      • @TomKarzes 这确实是一个特例,就像我提到的,修复很简单。说“它不起作用”确实有点不公平。
      【解决方案4】:

      其他答案很棒,但这个输入确实失败了。

      string1 = 'THE ACADEMY has'
      string2= '.CADEMY has taken'
      

      输出:

      >>> merge(string1,string2)
      'THE ACADEMY has.CADEMY has taken'
      >>> overlap(string1,string2)
      'THE ACADEMY has'
      

      但是有这个标准库difflib 证明对我来说是有效的!

      match = SequenceMatcher(None, string1,\
                              string2).find_longest_match\
                              (0, len(string1), 0, len(string2))
      
      print(match)  # -> Match(a=0, b=15, size=9)
      print(string1[: match.a + match.size]+string2[match.b + match.size:]) 
      

      输出:

      Match(a=5, b=1, size=10)
      THE ACADEMY has taken
      

      【讨论】:

      • 您的匹配规则在某种程度上是任意的。 ACADEMY 仅与 CADEMY 重叠在 .CADEMY 字符串上,因此点 . 应该保留。我敢肯定在某些情况下您的 SequenceMatcher 也会失败
      • 这是一个使用您的方法的失败案例:import difflib string1 = 'This is a nice ACADEMY' string2 = 'DEMY you know! nice' match = difflib.SequenceMatcher(None, string1, string2).find_longest_match(0, len(string1), 0, len(string2)) print(string1[: match.a + match.size]+string2[match.b + match.size:])。输出将是:This is a nice。正确吗? - 不
      • 投票结束这个问题过于广泛
      • 如果你能在你的question中指定这样的要求就好了。
      • @RomanPerekhrest 与您同在。此外,毗湿奴,如果您的问题与任何特定版本无关,请不要使用特定于版本的标签——这相当于标记垃圾邮件,所以请不要再这样做了。我删除它们是有原因的。
      【解决方案5】:

      您要替换的单词出现在第二个字符串中,因此您可以尝试以下操作:

      new_string=[string2.split()]
      new=[]
      new1=[j for item in new_string for j in item if j not in string1]
      new1.insert(0,string1)
      print(" ".join(new1))
      

      第一个测试用例:

      string1 = 'Hello how are you'
      string2 = 'are you doing now?'
      

      输出:

      Hello how are you doing now?
      

      第二个测试用例:

      string1 = 'This is a nice ACADEMY'
      string2 = 'DEMY you know!'
      

      输出:

      This is a nice ACADEMY you know!
      

      解释:

      首先,我们拆分第二个字符串,以便我们可以找到需要删除或替换的单词:

      new_string=[string2.split()]
      

      第二步,我们将使用 string1 检查此拆分器字符串的每个单词,如果该字符串中有任何单词而不是仅选择第一个字符串单词,则将该单词留在第二个字符串中:

      new1=[j for item in new_string for j in item if j not in string1]
      

      这个列表理解与:

      new1=[]
      for item in new_string:
          for j in item:
              if j not in string1:
                  new1.append(j)
      

      最后一步结合字符串和加入列表:

      new1.insert(0,string1)
      print(" ".join(new1))
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2023-03-29
        • 2013-09-13
        • 1970-01-01
        • 1970-01-01
        • 2016-04-20
        相关资源
        最近更新 更多