2010-03-08 18 views
59

Considere ..¿La manera más fácil de reemplazar una cadena usando un diccionario de reemplazos?

dict = { 
'Спорт':'Досуг', 
'russianA':'englishA' 
} 

s = 'Спорт russianA' 

Me gustaría reemplazar todas las claves de diccionario con sus respectivos valores dict en s.

+0

Esto podría no ser tan sencillo. Probablemente deberías tener un tokenizador explícito (por ejemplo '{'cat': 'russiancat'}' y "caterpillar"). También palabras superpuestas ('{'car': 'russiancar', 'pet': 'russianpet'}' y 'carpet'). – Joe

+2

También vea http://code.activestate.com/recipes/81330-single-pass-multiple-replace/ – ChristopheD

+1

Como nota aparte: creo que 'dict' es mejor evitarlo como nombre de variable, porque una variable de este nombre sombree la función incorporada del mismo nombre. – jochen

Respuesta

76

Usando re:

import re 

s = 'Спорт not russianA' 
d = { 
'Спорт':'Досуг', 
'russianA':'englishA' 
} 

pattern = re.compile(r'\b(' + '|'.join(d.keys()) + r')\b') 
result = pattern.sub(lambda x: d[x.group()], s) 
# Output: 'Досуг not englishA' 

Esto corresponderá con sólo palabras completas. Si no es necesario que utilice el patrón:

pattern = re.compile('|'.join(d.keys())) 

Tenga en cuenta que en este caso hay que ordenar las palabras que descienden por la longitud si algunos de sus entradas del diccionario son subseries de los demás.

+18

En caso de que las teclas del diccionario contengan caracteres como "^", "$" y "/", las claves deben escaparse antes de ensamblar la expresión regular. esto, '.join (d.keys())' podría ser reemplazado por '.join (re.escape (clave) para key en d.keys())'. – jochen

+0

Tenga en cuenta que el primer ejemplo (Досуг not englishA) solo funciona en python3. En python2 todavía me devuelve "Спорт not englishA" –

5

una manera, sin necesidad de volver

d = { 
'Спорт':'Досуг', 
'russianA':'englishA' 
} 

s = 'Спорт russianA'.split() 
for n,i in enumerate(s): 
    if i in d: 
     s[n]=d[i] 
print ' '.join(s) 
+2

Esto fallará si el dict tiene espacio en sus claves –

3

casi lo mismo que ghostdog74, aunque creado de manera independiente. Una diferencia, usando d.get() en lugar de d [] puede manejar elementos que no están en el diccionario.

>>> d = {'a':'b', 'c':'d'} 
>>> s = "a c x" 
>>> foo = s.split() 
>>> ret = [] 
>>> for item in foo: 
... ret.append(d.get(item,item)) # Try to get from dict, otherwise keep value 
... 
>>> " ".join(ret) 
'b d x' 
21

Se puede usar la función reduce:

reduce(lambda x, y: x.replace(y, dict[y]), dict, s) 
+13

Diferente a la solución de @Max Shawabkeh, usar 'reduce' aplica las sustituciones una tras otra. Como consecuencia, el intercambio de palabras con los diccionarios '{'rojo': 'verde', 'verde': 'rojo'}' no funciona con el enfoque basado en 'reducir', y las coincidencias superpuestas se transforman de manera impredecible. – jochen

+1

Un buen ejemplo de por qué las llamadas '.replace()' repetidas pueden tener consecuencias imprevistas: 'html.replace ('"', '"') .replace ('&', '&') '-try it on' html = '"foo"' '. – zigg

+0

Esto es innecesariamente complejo e ilegible en comparación con el ciclo desplegado como se muestra en las respuestas de [ChristopheD] (https://stackoverflow.com/a/2401481/216074), o [usuario2769207] (https : //stackoverflow.com/a/18748467/216074). – poke

16

Solución found here (me gusta su simplicidad):

def multipleReplace(text, wordDict): 
    for key in wordDict: 
     text = text.replace(key, wordDict[key]) 
    return text 
+8

Una vez más, como describió @jochen, esto corre el riesgo de una mala traducción si hay una clave que también es un valor. Un reemplazo de un solo pase sería lo mejor. – Chris

1

He utilizado este en una situación similar (mi cadena estaba todo en mayúsculas):

def translate(string, wdict): 
    for key in wdict: 
     string = string.replace(key, wdict[key].lower()) 
    return string.upper() 

esperanza de que ayuda de alguna manera. .. :)

+2

Es muy similar a la solución de ChristopheD. ¿Estás en desacuerdo con él? – hynekcer

0

Con la advertencia de que falla si la llave tiene espacio, esta es una solución comprimida similar a las respuestas ghostdog74 y extaneons:

d = { 
'Спорт':'Досуг', 
'russianA':'englishA' 
} 

s = 'Спорт russianA' 

' '.join(d.get(i,i) for i in s.split()) 
Cuestiones relacionadas