Eliminar solo la última aparición de las palabras de la cadena

Tengo una cadena y una serie de frases.

input_string = 'alice is a character from a fairy tale that lived in a wonder land. A character about whome no one knows much about' phrases_to_remove = ['wonderland', 'character', 'no one'] 

Ahora lo que quiero hacer es eliminar las últimas apariciones de las palabras en el conjunto phrases_to_remove de la input_string .

 output_string = 'alice is a character from a fairy tale that lived in a. A about whome knows much about' 

He escrito un método que toma la cadena de entrada y una array o solo una string para reemplazar y he usado el rsplit() para reemplazar las frases.

 def remove_words_from_end(actual_string: str, to_replace, occurrence: int): if isinstance(to_replace, list): output_string = actual_string for string in to_replace: output_string = ' '.join(output_string.rsplit(string, maxsplit=occurrence)) return output_string.strip() elif isinstance(to_replace, str): return ' '.join(actual_string.rsplit(to_replace, maxsplit=occurrence)).strip() else: raise TypeError('the value "to_replace" must be a string or a list of strings') 

El problema con el código es que no puedo eliminar las palabras que tienen una discrepancia de space . Por ejemplo wonder land y el wonderland .

¿Hay alguna manera de hacerlo sin comprometer mucho el rendimiento?

Usar re para manejar los posibles espacios en blanco es una posibilidad:

 import re def remove_last(word, string): pattern = ' ?'.join(list(word)) matches = list(re.finditer(pattern, string)) if not matches: return string last_m = matches[-1] sub_string = string[:last_m.start()] if last_m.end() < len(string): sub_string += string[last_m.end():] return sub_string def remove_words_from_end(words, string): words_whole = [word.replace(' ', '') for word in words] string_out = string for word in words: string_out = remove_last(word, string_out) return string_out 

Y ejecutando algunas pruebas:

 >>> input_string = 'alice is a character from a fairy tale that lived in a wonder land. A character about whome no one knows much about' >>> phrases_to_remove = ['wonderland', 'character', 'no one'] >>> remove_words_from_end(phrases_to_remove, input_string) 'alice is a character from a fairy tale that lived in a . A about whome knows much about' >>> phrases_to_remove = ['wonder land', 'character', 'noone'] >>> remove_words_from_end(phrases_to_remove, input_string) 'alice is a character from a fairy tale that lived in a . A about whome knows much about' 

En este ejemplo, el patrón de búsqueda de expresiones regulares es solo la palabra con un espacio posible ' ?' entre cada personaje.

En general, al comparar dos cadenas s1 y s2, podría estar comprobando si son iguales (el mismo tamaño y cada carácter es el mismo; lo que hace el método estándar usado) O (la parte que necesita implementar) si difieren en 1 en el tamaño y el carácter en el que se diferencian si hay un espacio. Una función de ejemplo que hace esto se escribe a continuación. En términos de rendimiento, esta es una comprobación O (n) donde n es la longitud de la cadena pero, independientemente de la comprobación inicial, también fue O (n).

 def almost_match(s1, s2): # If they have a single space of difference if len(s1) != len(s2) + 1 and len(s2) != len(s1) + 1: return False i = 0 # counter for s1 characters j = 0 # counter for s2 characters while i < len(s1) and j < len(s2): if s1[i] != s2[j]: if s1 == ' ': i = i + 1 continue elif s2 == ' ': j = j + 1 continue else: return False i = i + 1 j = j + 1 if j < len(s2) and s2[j] == ' ': j = j + 1 if i < len(s1) and s2[i] == ' ': i = i + 1 return i == len(s1) and j == len(s2) # require that both strings matched fully 

Para la última línea, tenga en cuenta que evita la posibilidad de hacer coincidir "abc" con "abcd". Esto se puede optimizar, pero esta es la idea general