Python: eliminació espais superflus

Python no té una funció específica per eliminar espais superflus (és a dir, eliminar tots els espais del principi i del final d’un text, i entre paraules deixar-hi només un espai).

Hi ha una manera molt pythònica de fer-ho:

" ".join(text_amb_espais.split())

I això és ràpid? Doncs comparem 3 alternatives amb timeit:

  • Aquesta de join i split
  • Un bucle pas a pas: mirar caràcter a caràcter si hauríem de posar-lo al resultat final, depenent de si aquest o l’anterior són espais.
  • Amb tantes substitucions com calgui de dos espais seguits a un.

El codi per mesurar-ho és:

from timeit import timeit

def eliminar_espais_split_join (text: str) -> str:
    return " ".join(text.split())

def eliminar_espais_posicio_a_posicio (text: str) -> str:
    anterior_es_espai = True
    sense_espais_redundants = ""
    for x in text:
        if x == " ":
            if not anterior_es_espai:
                sense_espais_redundants += x
                anterior_es_espai = True
        else:
            sense_espais_redundants += x
            anterior_es_espai = False

    if len(sense_espais_redundants) > 0:
        if sense_espais_redundants [-1] == " ":
            sense_espais_redundants = sense_espais_redundants[:-1]
    return sense_espais_redundants

def eliminar_espais_replace (text: str) -> str:
    r2 = text
    while (r1:= r2.replace("  ", " ")) != r2:
            r2 = r1
    if len(r2) > 0:
        if r2[0] == " ":
            r2 = r2[1:]
    if len(r2) > 0:
        if r2[-1] == " ":
            r2 = r2[:-1]
    return r2

TEXT_PROVA = "      Vivamus       quis        lacus     quis  sapien    elementum     finibus   et    sollicitudin nisi.   "

assert (eliminar_espais_posicio_a_posicio (TEXT_PROVA) == eliminar_espais_split_join(TEXT_PROVA))
assert (eliminar_espais_replace (TEXT_PROVA) == eliminar_espais_split_join(TEXT_PROVA))

EXECUCIONS = 100_000

temps = (timeit (lambda: eliminar_espais_split_join (TEXT_PROVA), number=EXECUCIONS),
         timeit (lambda: eliminar_espais_posicio_a_posicio (TEXT_PROVA), number=EXECUCIONS),
         timeit (lambda: eliminar_espais_replace(TEXT_PROVA), number=EXECUCIONS))

temps_minim = min(temps)

print (f"eliminar_espais_split_join: {temps [0] / temps_minim:.2f} vegades el mínim")
print (f"eliminar_espais_posicio_a_posicio: {temps [1] / temps_minim:.2f} vegades el mínim")
print (f"eliminar_espais_replace: {temps [2] / temps_minim:.2f} vegades el mínim")

I el resultat:

eliminar_espais_split_join: 1.00 vegades el mínim
eliminar_espais_replace: 2.25 vegades el mínim
eliminar_espais_posicio_a_posicio: 8.83 vegades el mínim

He provat algunes variants, sense que influeixin significativament en els resultats:

  • Sense fer servir l’operador walrus (notació := al while) a eliminar_espais_replace.
  • Amb substitucions de 2 i 3 espais concatenades a eliminar_espais_replace.
  • Amb un índex per accedir als diferents caràcters a posicio_a_posicio.

O sigui, he deixat l’split_join al codi, la manera més genuïna del Python és alhora la més ràpida.

Deixa un comentari

L'adreça electrònica no es publicarà. Els camps necessaris estan marcats amb *

This site uses Akismet to reduce spam. Learn how your comment data is processed.