web-dev-qa-db-fra.com

La chaîne Python remplace-t-elle deux choses à la fois?

Dis que j'ai une ficelle, "ab"

Je veux remplacer "a" par "b" et "b" par "a" d'un coup.

Ainsi, la chaîne de fin devrait indiquer "ba" et non "aa" ou "bb" et ne pas utiliser plus d'une ligne. Est-ce faisable?

31
WhatsInAName

Si vous devez échanger des variables, dites x et y , un modèle courant consiste à introduire une variable temporaire t pour faciliter l’échange: t = x; x = y; y = t.

Le même motif peut également être utilisé avec des chaînes:

>>> # swap a with b
>>> 'obama'.replace('a', '%temp%').replace('b', 'a').replace('%temp%', 'b')
'oabmb'

Cette technique n'est pas nouvelle. Il est décrit dans le document PEP 378 comme un moyen de convertir des séparateurs décimaux de style américain et européen en milliers (par exemple de 1,234,567.89 à 1.234.567,89. Guido a approuvé cette technique comme étant raisonnable.

43
Raymond Hettinger
import string
"abaababb".translate(string.maketrans("ab", "ba"))
# result: 'babbabaa'

Notez que cela ne fonctionne que pour les substitutions d'un caractère.

Pour des sous-chaînes ou des substitutions plus longues, ceci est un peu complexe, mais pourrait fonctionner

import re

def replace_all(repls, str):
    # return re.sub('|'.join(repls.keys()), lambda k: repls[k.group(0)], str)                                     
    return re.sub('|'.join(re.escape(key) for key in repls.keys()),
                  lambda k: repls[k.group(0)], str)                                     


text =  "i like apples, but pears scare me"
print replace_all({"Apple": "pear", "pear": "Apple"}, text)

Malheureusement cela ne fonctionnera pas si vous incluez des caractères spéciaux regexp vous ne pouvez pas utiliser les expressions rationnelles de cette façon :(

(Merci @ Timpietzcker)

20
Amadan

Si vous êtes d'accord avec deux lignes, c'est plus élégant.

d={'a':'b','b':'a'}
''.join(d[s] for s in "abaababbd" if s in d.keys())
7
Abhijit

Votre exemple est un peu abstrait, mais j’avais utilisé jadis cette recette pour créer une expression régulière permettant de remplacer plusieurs passes par passe. Voici ma version modifiée de celui-ci:

import re 

def multiple_replace(dict, text): 
  regex = re.compile("|".join(map(re.escape, dict.keys())))
  return regex.sub(lambda mo: dict[mo.group(0)], text) 

Notez que les clés (searchstrings) sont rééchappées.

Dans votre cas ce serait:

from utils import multiple_replace

print multiple_replace({
    "a": "b",
    "b": "a"
}, "ab") 

METTRE À JOUR:

A présent, ceci est fondamentalement le même que réponse d'Amadan

2
Bruce van der Kooij
>>> import re
>>> re.sub('.', lambda m: {'a':'b', 'b':'a'}.get(m.group(), m.group()), 'abc')
'bac'
1
kev
the_string="ab"
new_string=""

for x in range(len(the_string)):
    if the_string[x]=='a':
        new_string+='b'
        continue
    if the_string[x]=='b':
        new_string+='a'
        continue
    new_string+=the_string[x]

the_string=new_string

print the_string