strtr de php para python

php tiene la función strtr :

 strtr('aa-bb-cc', array('aa' => 'bbz', 'bb' => 'x', 'cc' => 'y')); # bbz-xy 

Reemplaza las claves del diccionario en una cadena con los valores correspondientes y (importante) no reemplaza las cadenas ya reemplazadas. Un bash ingenuo de escribir lo mismo en python:

 def strtr(strng, replace): for s, r in replace.items(): strng = strng.replace(s, r) return strng strtr('aa-bb-cc', {'aa': 'bbz', 'bb': 'x', 'cc': 'y'}) 

devuelve xz-xy que no es lo que queremos ( bb fue reemplazado nuevamente). ¿Cómo cambiar la función anterior para que se comporte como su contraparte php?

(Preferiría una respuesta sin expresiones regulares, si es posible).

Actualizaciones: algunas grandes respuestas aquí. Los cronometré y encontré que para cadenas cortas la versión de Gumbo parece ser la más rápida, en cadenas más largas el ganador es la solución:

 # 'aa-bb-cc' 0.0258 strtr_thg 0.0274 strtr_gumbo 0.0447 strtr_kojiro 0.0701 strtr_aix # 'aa-bb-cc'*10 0.1474 strtr_aix 0.2261 strtr_thg 0.2366 strtr_gumbo 0.3226 strtr_kojiro 

Mi propia versión (que está ligeramente optimizada de Gumbo):

 def strtr(strng, replace): buf, i = [], 0 while i < len(strng): for s, r in replace.items(): if strng[i:len(s)+i] == s: buf.append(r) i += len(s) break else: buf.append(strng[i]) i += 1 return ''.join(buf) 

Códigos y tiempos completos: https://gist.github.com/2889181

Aquí hay un algoritmo ingenuo:

Use un índice para recorrer el carácter de la cadena original por carácter y verifique si cada una de las cadenas de búsqueda es igual a la cadena del índice actual. Si se encuentra una coincidencia, presione la sustitución en un búfer y continúe con el índice por la longitud de la cadena coincidente. Si no se encuentra ninguna coincidencia, proceda con el índice en uno. Al final, concatene las cadenas en el búfer a una sola cadena.

 def strtr(strng, replace): buffer = [] i, n = 0, len(strng) while i < n: match = False for s, r in replace.items(): if strng[i:len(s)+i] == s: buffer.append(r) i = i + len(s) match = True break if not match: buffer.append(strng[i]) i = i + 1 return ''.join(buffer) 

Lo siguiente usa expresiones regulares para hacerlo:

 import re def strtr(s, repl): pattern = '|'.join(map(re.escape, sorted(repl, key=len, reverse=True))) return re.sub(pattern, lambda m: repl[m.group()], s) print(strtr('aa-bb-cc', {'aa': 'bbz', 'bb': 'x', 'cc': 'y'})) 

Al igual que la versión de PHP, esto da preferencia a coincidencias más largas.

 def strtr(strng, replace): if replace and strng: s, r = replace.popitem() return r.join(strtr(subs, dict(replace)) for subs in strng.split(s)) return strng j=strtr('aa-bb-cc', {'aa': 'bbz', 'bb': 'x', 'cc': 'y'}) assert j=='bbz-x-y', j 

str.translate es el equivalente, pero solo se puede asignar a caracteres individuales.

Las respuestas en este hilo están tan desactualizadas. Aquí vamos…

Opción # 1: Use la función str.format () para manejar esto:

 "Hello there {first_name} {last_name}".format(first_name="Bob", last_name="Roy") 

Opción # 2: usar la clase de plantilla

 from string import Template t = Template('Hello there $first_name $last_name') t.substitute(first_name="Bob", last_name="Roy") 

Referencia: Python String Formatting Best Practices