2010-03-08 9 views
59

Tenir compte ..Le moyen le plus simple de remplacer une chaîne à l'aide d'un dictionnaire de remplacements?

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

s = 'Спорт russianA' 

Je voudrais remplacer toutes les clés de dict avec leurs valeurs respectives dans dict s.

+0

Cela peut ne pas être si simple. Vous devriez probablement avoir un tokenizer explicite (par exemple '{'cat': 'russiancat'}' et 'caterpillar'). Aussi des mots qui se chevauchent ('{'car': 'russiancar', 'pet': 'russianpet'}' et 'tapis'). – Joe

+2

Voir également http://code.activestate.com/recipes/81330-single-pass-multiple-replace/ – ChristopheD

+1

En aparté: Je pense que «dict» est préférable d'éviter comme nom de variable, car une variable de ce nom serait ombre la fonction intégrée du même nom. – jochen

Répondre

76

En utilisant 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' 

Cela correspond à tous les mots seulement. Si vous n'avez pas besoin que, utilisez le modèle:

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

Notez que dans ce cas, vous devez trier les mots en ordre décroissant, longueur si certains de vos entrées du dictionnaire sont d'autres sous-chaînes.

+18

Si les clés du dictionnaire contiennent des caractères tels que "^", "$" et "/", les clés doivent être échappées avant que l'expression régulière ne soit assemblée. ceci, '.join (d.keys())' pourrait être remplacé par '.join (re.escape (clé) pour clé dans d.keys())'. – jochen

+0

Veuillez noter que le premier exemple (Досуг pas englishA) ne fonctionne que dans python3. En python2 il me renvoie toujours "Спорт not englishA" –

5

une façon, sans re

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

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

Cela échouera si la dict a de l'espace dans ses touches –

3

Presque la même que ghostdog74, bien que créé de façon indépendante. Une différence, en utilisant d.get() au lieu de d [] peut gérer des éléments qui ne sont pas dans le dict.

>>> 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

Vous pouvez utiliser la fonction reduce:

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

Différent de la solution de @ Max Shawabkeh, l'utilisation de 'reduce' applique les substitutions les unes après les autres. En conséquence, échanger des mots en utilisant les dictionnaires '{'red': 'green', 'green': 'red'}' ne fonctionne pas avec l'approche 'reduce', et les correspondances qui se chevauchent sont transformées de façon imprévisible. – jochen

+1

Un bon exemple de pourquoi les appels '.replace()' répétés peuvent avoir des conséquences inattendues: 'html.replace ('"', '"') .replace ('&', '&') '-telle sur' html = '"foo"'. – zigg

+0

Ceci est inutilement complexe et illisible par rapport à la boucle dépliée comme indiqué dans les réponses de [ChristopheD] (https://stackoverflow.com/a/2401481/216074), ou [user2769207] (https : //stackoverflow.com/a/18748467/216074) – poke

16

Solution found here (J'aime sa simplicité):

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

Encore une fois, comme @jochen décrit, cela risque une mauvaise traduction s'il y a une clé qui est aussi une valeur. Un remplacement à un seul passage serait le meilleur. – Chris

1

J'ai utilisé ce dans une situation similaire (ma chaîne était en majuscules):

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

espoir qui aide d'une certaine façon. .. :)

+2

C'est très similaire à la solution de ChristopheD. Êtes-vous en désaccord avec lui? – hynekcer

0

Avec l'avertissement qu'il échoue si la clé a de l'espace, c'est une solution compressée semblable à ghostdog74 et extaneons réponses:

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

s = 'Спорт russianA' 

' '.join(d.get(i,i) for i in s.split()) 
Questions connexes