Saltar al contenido

La mejor forma de reemplazar varios caracteres en un string?

Hacemos una revisión exhaustiva cada una de las secciones en nuestro sitio web con el objetivo de mostrarte en todo momento información con la mayor veracidad y actual.

Solución:

Reemplazo de dos personajes

Calculé todos los métodos en las respuestas actuales junto con uno adicional.

Con una entrada string de abc&def#ghi y reemplazando & -> & y # -> #, la forma más rápida era encadenar los reemplazos de esta manera: text.replace('&', '&').replace('#', '#').

Tiempos para cada función:

  • a) 1000000 bucles, lo mejor de 3: 1,47 μs por bucle
  • b) 1000000 bucles, lo mejor de 3: 1,51 μs por bucle
  • c) 100000 bucles, lo mejor de 3: 12,3 μs por bucle
  • d) 100000 bucles, lo mejor de 3:12 μs por bucle
  • e) 100000 bucles, lo mejor de 3: 3,27 μs por bucle
  • f) 1000000 bucles, lo mejor de 3: 0,817 μs por bucle
  • g) 100000 bucles, lo mejor de 3: 3,64 μs por bucle
  • h) 1000000 bucles, lo mejor de 3: 0,927 μs por bucle
  • i) 1000000 bucles, lo mejor de 3: 0,814 μs por bucle

Aquí están las funciones:

def a(text):
    chars = "&#"
    for c in chars:
        text = text.replace(c, "\" + c)


def b(text):
    for ch in ['&','#']:
        if ch in text:
            text = text.replace(ch,"\"+ch)


import re
def c(text):
    rx = re.compile('([&#])')
    text = rx.sub(r'\1', text)


RX = re.compile('([&#])')
def d(text):
    text = RX.sub(r'\1', text)


def mk_esc(esc_chars):
    return lambda s: ''.join(['\' + c if c in esc_chars else c for c in s])
esc = mk_esc('&#')
def e(text):
    esc(text)


def f(text):
    text = text.replace('&', '&').replace('#', '#')


def g(text):
    replacements = "&": "&", "#": "#"
    text = "".join([replacements.get(c, c) for c in text])


def h(text):
    text = text.replace('&', r'&')
    text = text.replace('#', r'#')


def i(text):
    text = text.replace('&', r'&').replace('#', r'#')

Programado así:

python -mtimeit -s"import time_functions" "time_functions.a('abc&def#ghi')"
python -mtimeit -s"import time_functions" "time_functions.b('abc&def#ghi')"
python -mtimeit -s"import time_functions" "time_functions.c('abc&def#ghi')"
python -mtimeit -s"import time_functions" "time_functions.d('abc&def#ghi')"
python -mtimeit -s"import time_functions" "time_functions.e('abc&def#ghi')"
python -mtimeit -s"import time_functions" "time_functions.f('abc&def#ghi')"
python -mtimeit -s"import time_functions" "time_functions.g('abc&def#ghi')"
python -mtimeit -s"import time_functions" "time_functions.h('abc&def#ghi')"
python -mtimeit -s"import time_functions" "time_functions.i('abc&def#ghi')"

Reemplazo de 17 caracteres

Aquí hay un código similar para hacer lo mismo pero con más caracteres para escapar ( `* _ > # + -.! $):

def a(text):
    chars = "\`*_[]()>#+-.!$"
    for c in chars:
        text = text.replace(c, "\" + c)


def b(text):
    for ch in ['\','`','*','_','','','[',']','(',')','>','#','+','-','.','!','$',''']:
        if ch in text:
            text = text.replace(ch,"\"+ch)


import re
def c(text):
    rx = re.compile('([&#])')
    text = rx.sub(r'\1', text)


RX = re.compile('([\`*_[]()>#+-.!$])')
def d(text):
    text = RX.sub(r'\1', text)


def mk_esc(esc_chars):
    return lambda s: ''.join(['\' + c if c in esc_chars else c for c in s])
esc = mk_esc('\`*_[]()>#+-.!$')
def e(text):
    esc(text)


def f(text):
    text = text.replace('\', '\\').replace('`', '`').replace('*', '*').replace('_', '_').replace('', '').replace('', '').replace('[', '[').replace(']', ']').replace('(', '(').replace(')', ')').replace('>', '>').replace('#', '#').replace('+', '+').replace('-', '-').replace('.', '.').replace('!', '!').replace('$', '$')


def g(text):
    replacements = 
        "\": "\\",
        "`": "`",
        "*": "*",
        "_": "_",
        "": "",
        "": "",
        "[": "[",
        "]": "]",
        "(": "(",
        ")": ")",
        ">": ">",
        "#": "#",
        "+": "+",
        "-": "-",
        ".": ".",
        "!": "!",
        "$": "$",
    
    text = "".join([replacements.get(c, c) for c in text])


def h(text):
    text = text.replace('\', r'\')
    text = text.replace('`', r'`')
    text = text.replace('*', r'*')
    text = text.replace('_', r'_')
    text = text.replace('', r'')
    text = text.replace('', r'')
    text = text.replace('[', r'[')
    text = text.replace(']', r']')
    text = text.replace('(', r'(')
    text = text.replace(')', r')')
    text = text.replace('>', r'>')
    text = text.replace('#', r'#')
    text = text.replace('+', r'+')
    text = text.replace('-', r'-')
    text = text.replace('.', r'.')
    text = text.replace('!', r'!')
    text = text.replace('$', r'$')


def i(text):
    text = text.replace('\', r'\').replace('`', r'`').replace('*', r'*').replace('_', r'_').replace('', r'').replace('', r'').replace('[', r'[').replace(']', r']').replace('(', r'(').replace(')', r')').replace('>', r'>').replace('#', r'#').replace('+', r'+').replace('-', r'-').replace('.', r'.').replace('!', r'!').replace('$', r'$')

Aquí están los resultados para la misma entrada. string abc&def#ghi:

  • a) 100000 bucles, lo mejor de 3: 6,72 μs por bucle
  • B) 100000 bucles, lo mejor de 3: 2,64 μs por bucle
  • c) 100000 bucles, lo mejor de 3: 11,9 μs por bucle
  • d) 100000 bucles, lo mejor de 3: 4,92 μs por bucle
  • mi) 100000 bucles, lo mejor de 3: 2,96 μs por bucle
  • f) 100000 bucles, lo mejor de 3: 4,29 μs por bucle
  • g) 100000 bucles, lo mejor de 3: 4,68 μs por bucle
  • h) 100000 bucles, lo mejor de 3: 4,73 μs por bucle
  • i) 100000 bucles, lo mejor de 3: 4,24 μs por bucle

Y con una entrada más larga string (## *Something* and [another] thing in a longer sentence with more things to replace$):

  • a) 100000 bucles, lo mejor de 3: 7,59 μs por bucle
  • b) 100000 bucles, lo mejor de 3: 6,54 μs por bucle
  • c) 100000 bucles, lo mejor de 3: 16,9 μs por bucle
  • d) 100000 bucles, lo mejor de 3: 7,29 μs por bucle
  • e) 100000 bucles, lo mejor de 3: 12,2 μs por bucle
  • F) 100000 bucles, lo mejor de 3: 5,38 μs por bucle
  • g) 10000 bucles, lo mejor de 3: 21,7 μs por bucle
  • h) 100000 bucles, lo mejor de 3: 5,7 μs por bucle
  • I) 100000 bucles, lo mejor de 3: 5,13 μs por bucle

Añadiendo un par de variantes:

def ab(text):
    for ch in ['\','`','*','_','','','[',']','(',')','>','#','+','-','.','!','$',''']:
        text = text.replace(ch,"\"+ch)


def ba(text):
    chars = "\`*_[]()>#+-.!$"
    for c in chars:
        if c in text:
            text = text.replace(c, "\" + c)

Con la entrada más corta:

  • ab) 100000 bucles, lo mejor de 3: 7,05 μs por bucle
  • ba) 100000 bucles, lo mejor de 3: 2,4 μs por bucle

Con la entrada más larga:

  • ab) 100000 bucles, lo mejor de 3: 7,71 μs por bucle
  • ba) 100000 bucles, lo mejor de 3: 6,08 μs por bucle

Entonces voy a usar ba para mayor legibilidad y velocidad.

Apéndice

Impulsado por haccks en los comentarios, una diferencia entre ab y ba es el if c in text: cheque. Probémoslos contra dos variantes más:

def ab_with_check(text):
    for ch in ['\','`','*','_','','','[',']','(',')','>','#','+','-','.','!','$',''']:
        if ch in text:
            text = text.replace(ch,"\"+ch)

def ba_without_check(text):
    chars = "\`*_[]()>#+-.!$"
    for c in chars:
        text = text.replace(c, "\" + c)

Tiempos en μs por bucle en Python 2.7.14 y 3.6.3, y en una máquina diferente del conjunto anterior, por lo que no se pueden comparar directamente.

╭────────────╥──────┬───────────────┬──────┬──────────────────╮
│ Py, input  ║  ab  │ ab_with_check │  ba  │ ba_without_check │
╞════════════╬══════╪═══════════════╪══════╪══════════════════╡
│ Py2, short ║ 8.81 │    4.22       │ 3.45 │    8.01          │
│ Py3, short ║ 5.54 │    1.34       │ 1.46 │    5.34          │
├────────────╫──────┼───────────────┼──────┼──────────────────┤
│ Py2, long  ║ 9.3  │    7.15       │ 6.85 │    8.55          │
│ Py3, long  ║ 7.43 │    4.38       │ 4.41 │    7.02          │
└────────────╨──────┴───────────────┴──────┴──────────────────┘

Podemos concluir que:

  • Aquellos con el cheque son hasta 4 veces más rápidos que aquellos sin el cheque

  • ab_with_check está ligeramente a la cabeza en Python 3, pero ba (con cheque) tiene una ventaja mayor en Python 2

  • Sin embargo, la mayor lección aquí es Python 3 es hasta 3 veces más rápido que Python 2! ¡No hay una gran diferencia entre el más lento en Python 3 y el más rápido en Python 2!

>>> string="abc&def#ghi"
>>> for ch in ['&','#']:
...   if ch in string:
...      string=string.replace(ch,"\"+ch)
...
>>> print string
abc&def#ghi

Aquí hay un método python3 usando str.translate y str.maketrans:

s = "abc&def#ghi"
print(s.translate(str.maketrans('&': '&', '#': '#')))

El impreso string es abc&def#ghi.

Comentarios y valoraciones

Nos puedes sustentar nuestra función poniendo un comentario o valorándolo te damos las gracias.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *