2010-11-11 16 views
10

¿Cuál es una manera elegante de buscar una cadena dentro de otra cadena en Python, pero solo si la subcadena está dentro de palabras completas, no es parte de una palabra?Buscar subcadena en cadena pero solo si las palabras completas?

Quizás un ejemplo demostrará lo que quiero decir:

string1 = "ADDLESHAW GODDARD" 
string2 = "ADDLESHAW GODDARD LLP" 
assert string_found(string1, string2) # this is True 
string1 = "ADVANCE" 
string2 = "ADVANCED BUSINESS EQUIPMENT LTD" 
assert not string_found(string1, string2) # this should be False 

¿Cómo puedo mejor escribir una función llamada string_found que va a hacer lo que necesito? Pensé que tal vez podría eludir con algo como esto:

def string_found(string1, string2): 
    if string2.find(string1 + " "): 
     return True 
    return False 

Pero que no se siente muy elegante, y además no se correspondería con cadena1 si era al final de cadena2. Tal vez necesito una expresión regular? (miedo arg regex)

Respuesta

5

Aquí hay una manera de hacerlo sin una expresión regular (según se solicite) suponiendo que desea que cualquier espacio en blanco sirva como separador de palabras.

import string 

def find_substring(needle, haystack): 
    index = haystack.find(needle) 
    if index == -1: 
     return False 
    if index != 0 and haystack[index-1] not in string.whitespace: 
     return False 
    L = index + len(needle) 
    if L < len(haystack) and haystack[L] not in string.whitespace: 
     return False 
    return True 

Y aquí algo de demo code (teclado es una gran idea: Gracias a Felix Kling por recordármelo)

+0

De nada :) –

+0

Solo asegúrese de "guardar" las pastillas del teclado de código, para que no caduquen. (Incluyo un enlace en un comentario del teclado numérico, solo para mis propias notas más tarde, también.) –

+1

Para aquellos que quieren asegurarse de que la puntuación y el espacio en blanco se consideren un delimitador de palabra completa válido ... modifique el código anterior como sigue: '' 'no en (string.whitespace + string.punctuation)' '' También tenga en cuenta que esta función es más del doble de eficiente que la alternativa RegEx propuesta, así que ... si la usa mucho, esta función es el camino a seguir. –

19

Usted puede utilizar regular expressions y la palabra carácter especial límite \b (destacado por mí):

Hace coincidir la cadena vacía, pero solo al principio o al final de una palabra. Una palabra se define como una secuencia de caracteres alfanuméricos o de subrayado, por lo que el final de una palabra se indica mediante espacios en blanco o un carácter no subrayado, no subrayado. Tenga en cuenta que \b se define como el límite entre \w y \W, por lo que el conjunto preciso de caracteres que se consideran alfanuméricos depende de los valores de los indicadores UNICODE y LOCALE. Dentro de un rango de caracteres, \b representa el carácter de retroceso, para compatibilidad con los literales de cadenas de Python.

def string_found(string1, string2): 
    if re.search(r"\b" + re.escape(string1) + r"\b", string2): 
     return True 
    return False 

Demo


Si límites de las palabras son sólo espacios en blanco para usted, usted también podría salirse con espacios en blanco antes y anexas a sus cadenas:

def string_found(string1, string2): 
    string1 = " " + string1.strip() + " " 
    string2 = " " + string2.strip() + " " 
    if string2.find(string1): 
     return True 
    return False 
+1

Up-votado por la sugerencia teórica. Su script, OTOH, no funcionará. ''\ b'' es la secuencia de escape para el carácter de retroceso ('' \ x08'').Yo sugeriría 'r '\ b% s \ b'% (re.escape (string1))' como el primer parámetro para 're.search()' en lugar. De hecho, toda esa función podría reducirse a 'return re.search (r '\ b% s \ b'% (re.escape (string1)), string2) no es None' – Walter

+1

@Walter: No estoy seguro acerca de' \ b'. Se dice: * Dentro de un ** rango de caracteres **, '\ b' representa el carácter de retroceso, ... * Al menos funciona para mí. Pero sí, la sustitución de cadenas también es agradable :) –

+0

cuando \ b está dentro de un rango de caracteres [a-z0-9 \ b] ...? \ b debería funcionar, y lo hice en la breve prueba que hice –

0

Un enfoque usando el re, o el módulo regex, que debería realizar esta tarea es:

import re 

string1 = "pizza pony" 
string2 = "who knows what a pizza pony is?" 

search_result = re.search(r'\b' + string1 + '\W', string2) 

print(search_result.group()) 
Cuestiones relacionadas