【问题标题】:How to detect identical part(s) inside string?如何检测字符串中的相同部分?
【发布时间】:2010-04-26 09:54:06
【问题描述】:

我尝试将decoding algorithm wanted 问题分解为更小的问题。这是第一部分。

问题:

  • 两个字符串:s1 和 s2
  • s1 的一部分与 s2 的一部分相同
  • 空格是分隔符
  • 如何提取相同的部分?

示例 1:

s1 = "12 November 2010 - 1 visitor"
s2 = "6 July 2010 - 100 visitors"

the identical parts are "2010", "-", "1" and "visitor"

示例 2:

s1 = "Welcome, John!"
s2 = "Welcome, Peter!"

the identical parts are "Welcome," and "!"

示例 3:(澄清“!”示例)

s1 = "Welcome, Sam!"
s2 = "Welcome, Tom!"

the identical parts are "Welcome," and "m!"

首选 Python 和 Ruby。谢谢

【问题讨论】:

  • 为什么“1”在第一个例子中是相同的?
  • “1”与“100”的第一个字符相同,类似于“visitor”是“visitors”的一部分
  • 在我看来 1 和 100 绝不相同。您能否准确定义“相同”的含义
  • 相同的部分是否必须在相同的相应“单词”中?例如,如果s1 = "2010"s2 = "something else 2010"2010 是否仍然是“相同的部分”?
  • 相同:一个字符串的子字符串与另一个字符串的子字符串完全相等

标签: python ruby regex pattern-matching


【解决方案1】:

编辑:更新了此示例以适用于所有示例,包括 #1:

def scan(s1, s2):
    # Find the longest match where s1 starts with s2
    # Returns None if no matches
    l = len(s1)
    while 1:
        if not l:
            return None
        elif s1[:l] == s2[:l]:
            return s1[:l]
        else:
            l -= 1

def contains(s1, s2):
    D = {} # Remove duplicates using a dict
    L1 = s1.split(' ')
    L2 = s2.split(' ')

    # Don't add results which have already 
    # been processed to satisfy example #1!
    DProcessed = {}

    for x in L1:
        yy = 0
        for y in L2:
            if yy in DProcessed:
                yy += 1
                continue

            # Scan from the start to the end of the words
            a = scan(x, y)
            if a: 
                DProcessed[yy] = None
                D[a] = None
                break

            # Scan from the end to the start of the words
            a = scan(x[::-1], y[::-1])
            if a: 
                DProcessed[yy] = None
                D[a[::-1]] = None
                break
            yy += 1

    return list(D.keys())

print contains("12 November 2010 - 1 visitor",
               "6 July 2010 - 100 visitors")
print contains("Welcome, John!",
               "Welcome, Peter!")
print contains("Welcome, Sam!",
               "Welcome, Tom!")

哪些输出:

['1', 'visitor', '-', '2010']
['Welcome,', '!']
['Welcome,', 'm!']

【讨论】:

    【解决方案2】:

    例如1

    >>> s1 = 'November 2010 - 1 visitor'
    >>> s2 = '6 July 2010 - 100 visitors'
    >>> 
    >>> [i for i in s1.split() if any(j for j in s2.split() if i in j)]
    ['2010', '-', '1', 'visitor']
    >>>
    

    两者都有

    >>> s1 = "Welcome, John!"
    >>> s2 = "Welcome, Peter!"
    >>> [i for i in s1.replace('!',' !').split() if any(j for j in s2.replace('!',' !').split() if i in j)]
    ['Welcome,', '!']
    >>>
    

    注意:上面的代码对例子3不起作用,是刚刚添加的OP

    【讨论】:

    • 这在第二个例子中没有得到!,因为(我认为)提问者希望 s1 中的任何子字符串与 s2 中的任何子字符串匹配(不包括空格)。
    • @clyfe,我已将 .startswith 更改为 in 以支持这一点。
    • 原谅我的无知,为什么需要replace('!', "!")?
    • @Horace,因为拆分方法需要空格来拆分它。
    • @S.Mark,请查看示例 3
    【解决方案3】:
    s1 = "12 November 2010 - 1 visitor"
    s2 = "6 July 2010 - 100 visitors"
    l1 = s1.split()
    for item in l1:
       if item in s2:
          print item
    

    这会在空白处拆分。

    同样在字边界上拆分的解决方案(为了捕获示例 2 中的 !)在 Python 中不起作用,因为 re.split() 不会在零长度匹配上拆分。

    第三个示例,甚至将单词的任何子字符串都设为潜在匹配,这使得事情变得更加复杂,因为有许多可能的变化(对于1234,我必须检查1234,@987654326 @、2341223341234,每多一个数字,排列的数量就会成倍增加。

    【讨论】:

    • 我认为这个问题想拆分“任何东西”(即任何不包含标点符号的子字符串都是可能的匹配项)
    【解决方案4】:

    完整的 Ruby 解决方案:

    def start_similar(i, j)
        front = ''
        for ix in (0...([i.size, j.size].min))
          if i[ix] == j[ix] then
            front += i[ix].chr
          else
            break
          end
        end
        return front
    end
    
    def back_similar(i, j)
        back = ''
        for ix in (0...([i.size, j.size].min)).to_a.reverse
          dif = i.size < j.size ? j.size - i.size : i.size - j.size
          ci = i[ i.size < j.size ? ix : ix + dif ]
          cj = j[ i.size > j.size ? ix : ix + dif ]
          if ci == cj then
            back = ci.chr + back
          else
            break
          end
        end
        return back
    end
    
    def scan(x, y)
        a, b = x.split(' '), y.split(' ')
        result = []
        for i in a do
          for j in b do
            result << start_similar(i, j)
            result << back_similar(i, j)
          end
        end
        return result.uniq.select do |r| not r.empty? end
    end
    
    puts scan(
        "12 November 2010 - 1 visitor",
        "6 July 2010 - 100 visitors"
    ).inspect
    # ["1", "2010", "0", "-", "visitor"]
    
    puts scan(
        "Welcome, John!",
        "Welcome, Peter!"
    ).inspect
    # ["Welcome,", "!"]
    
    puts scan(
        "Welcome, Sam!",
        "Welcome, Tom!"
    ).inspect
    # ["Welcome,", "m!"]
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-11-03
      • 1970-01-01
      • 2021-12-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-07-16
      相关资源
      最近更新 更多