Encuentra una subcadena común entre dos cadenas
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.
Para completar, difflib
la 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))
También se podría considerar os.path.commonprefix
que 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.
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))