Encuentra una subcadena común entre dos cadenas

Resuelto NorthSide asked hace 11 años • 20 respuestas

Me gustaría comparar 2 cadenas y mantener las coincidentes, separándolas donde falla la comparación.

Entonces si tengo 2 cadenas:

string1 = "apples"
string2 = "appleses"

answer = "apples"

Otro ejemplo, ya que la cadena podría tener más de una palabra:

string1 = "apple pie available"
string2 = "apple pies"

answer = "apple pie"

Estoy seguro de que existe una forma sencilla de hacer esto en Python, pero no puedo resolverla. Se agradece cualquier ayuda y explicación.

NorthSide avatar Sep 10 '13 16:09 NorthSide
Aceptado

Para completar, difflibla biblioteca estándar proporciona un montón de utilidades de comparación de secuencias. Por ejemplo find_longest_match, que encuentra la subcadena común más larga cuando se usa en cadenas. Uso de ejemplo:

from difflib import SequenceMatcher

string1 = "apple pie available"
string2 = "come have some apple pies"

match = SequenceMatcher(None, string1, string2).find_longest_match()

print(match)  # -> Match(a=0, b=15, size=9)
print(string1[match.a:match.a + match.size])  # -> apple pie
print(string2[match.b:match.b + match.size])  # -> apple pie

Si está utilizando una versión anterior a la 3.9, debe llamar find_longest_match()con los siguientes argumentos:

SequenceMatcher(None, string1, string2).find_longest_match(0, len(string1), 0, len(string2))
RickardSjogren avatar Sep 09 '2016 06:09 RickardSjogren

También se podría considerar os.path.commonprefixque funciona con caracteres y, por lo tanto, puede usarse para cualquier cadena.

import os
common = os.path.commonprefix(['apple pie available', 'apple pies'])
assert common == 'apple pie'

Como indica el nombre de la función, esto solo considera el prefijo común de dos cadenas.

jonas avatar Nov 07 '2018 14:11 jonas
def common_start(sa, sb):
    """ returns the longest common substring from the beginning of sa and sb """
    def _iter():
        for a, b in zip(sa, sb):
            if a == b:
                yield a
            else:
                return

    return ''.join(_iter())
>>> common_start("apple pie available", "apple pies")
'apple pie'

O de una forma un poco más extraña:

def stop_iter():
    """An easy way to break out of a generator"""
    raise StopIteration

def common_start(sa, sb):
    return ''.join(a if a == b else stop_iter() for a, b in zip(sa, sb))

Que podría ser más legible como

def terminating(cond):
    """An easy way to break out of a generator"""
    if cond:
        return True
    raise StopIteration

def common_start(sa, sb):
    return ''.join(a for a, b in zip(sa, sb) if terminating(a == b))
Eric avatar Sep 10 '2013 09:09 Eric