Estoy tratando de hacer un script simple que reemplace todas las apariciones de cierto grupo o conjunto de caracteres (o conjunto de cadenas) en el texto.

En este caso, intentaré reemplazar todas las letras "a, e, i, o, u" con cierta cadena.

Mi guión:

def replace_all(text, repl):
    text1 = text.replace("a", repl)
    text2 = text1.replace("e", repl)
    text3 = text2.replace("i", repl)
    text4 = text3.replace("o", repl)
    text5 = text4.replace("u", repl)
    return text5

¿Hay alguna forma más sencilla de hacerlo? ¿Qué sucede si necesito reemplazar un grupo más grande de caracteres o cadenas? Encadenarlo así no parece ser realmente efectivo entonces.

Esta es quizás una pregunta primitiva. Sin embargo, todavía estoy en la fase de aprendizaje, así que tal vez lo obtenga en lecciones posteriores. Gracias de antemano por cualquier consejo.

4
Blacho 20 ene. 2018 a las 01:42

3 respuestas

La mejor respuesta

Mi conocimiento me dice que hay 3 diferentes formas de hacer esto, todas las cuales son más cortas que su método:

  • Usando un for-loop
  • Usando un generator-comprehension
  • Usando regular expressions

Primero, usando un for-loop. Esta es probablemente la mejoría más directa para su código y esencialmente solo reduce las líneas 5 con .replace hasta 2:

def replace_all(text, repl):
    for c in "aeiou":
        text = text.replace(c, repl)
    return text

También puede hacerlo en una línea utilizando un generator-comprehension, combinado con el método str.join. Esto sería más rápido (si eso es importante) ya que es de complejidad O(n) ya que revisaremos cada carácter y lo evaluaremos una vez (el primer método es la complejidad O(n^5) ya que Python realizará un bucle hasta text cinco veces para los diferentes reemplazos) .

Entonces, este método es simplemente:

def replace_all(text, repl):
    return ''.join(repl if c in 'aeiou' else c for c in text)

Finalmente, podemos usar re.sub para sustituir Todos los caracteres del conjunto: [aeiou] con el texto repl. Esta es la solución más corta y probablemente lo que recomendaría:

import re
def replace_all(text, repl):
    return re.sub('[aeiou]', repl, text)

Como dije al principio, todos estos métodos completan la tarea, por lo que no tiene sentido proporcionar casos de prueba individuales, pero funcionan como se ve en esta prueba:

>>> replace_all('hello world', 'x')
'hxllx wxrld'

Actualizar

Me ha llamado la atención un nuevo método: str.translate.

>>> {c:'x' for c in 'aeiou'}
{'a': 'x', 'e': 'x', 'i': 'x', 'o': 'x', 'u': 'x'}
>>> 'hello world'.translate({ord(c):'x' for c in 'aeiou'})
'hxllx wxrld'

Este método también es O(n), por lo que es tan eficiente como los dos anteriores.

6
Joe Iddon 30 may. 2019 a las 17:52

Entonces, lo que estás haciendo es perfectamente válido, sin embargo, hay mejores formas.

Aquí hay algunas soluciones, con tiempos de ejecución tomados sobre 100000 bucles.

La firma principal:

Los objetivos son los caracteres que desea reemplazar, repl es el carácter de reemplazo.

def replace_all(text, targets=['a', 'e', 'i', 'o', 'u'], repl='_'):
    text = # Something here to swap characters as an array
    return ''.join(text) # Stitch it back together

Bytearray

Bytearray es una estructura de datos mutable que contiene una lista de los propios caracteres . Como estructura de datos, aparentemente es la opción ideal, las cadenas en python son inmutables, esto funciona para evitar la construcción / destrucción constante.

[chr(c) if chr(c) not in targets else repl for c in bytearray(text, 'utf-8')]

Se ejecuta en 0.365

Sin bytearray

Esto opera en una lista simple, la lista en sí es mutable, pero los caracteres son cadenas, por lo tanto aquí hay alguna modificación de estructuras técnicamente inmutables.

[c if c not in targets else repl for c in text]

Corre en 0.179

Mapa

Esto asigna la función a cada carácter en la cadena.

map(lambda c: c if c not in targets else repl, text) 

Se ejecuta en 0.265

0
Thomas Howard 19 ene. 2018 a las 23:38

Este es un buen lugar para una expresión regular:

import re

def replace_all(text, repl):
    return re.sub('[aeiou]', repl, text)

Esto funcionará para el caso en su pregunta, donde está reemplazando caracteres individuales. Si desea reemplazar un conjunto de cadenas más largas:

def replace_all(text, to_replace, replacement):
    pattern = '|'.join(to_replace)
    return re.sub(pattern, replacement, text)

>>> replace_all('this is a thing', ['thi','a'], 'x')
'xs is x xng'
1
Nathan Vērzemnieks 19 ene. 2018 a las 23:02