Member of The Internet Defense League Últimos cambios
Últimos Cambios
Blog personal: El hilo del laberinto Geocaching

Manipulación rápida de cadenas en Python

Última Actualización: 21 de Enero de 2003 - Martes

En Python, al igual que ocurre con Java, cuando se manipulan cadenas se crean y se destruyen objetos constantemente. Ello supone un mayor uso de memoria y, sobre todo, una baja eficiencia.

Pero haciendo un uso inteligente de las características del lenguaje, es posible optimizar estas operaciones de forma considerable.

Los siguientes ejemplos utilizan Python 2.2.2, sobre una máquina UltraSparc I:

Eliminación de tags HTML:

Se busca y elimina los textos que aparezcan entre < >.

  • Opción 1:
    from time import time
    def eliminaTags1(texto) :
      t=time()
      a=0
      while a>=0 :
        a=texto.find("<")
        if a>=0 :
           b=texto.find(">",a)
           texto=texto[:a]+texto[b+1:]
      print time()-t
      return texto
    

    En esta opción, sencilla, eliminar cada tag supone crear tres cadenas nuevas, y eliminar una cadena antigua y dos nuevas.

  • Opción 2:
    from time import time
    def eliminaTags2(texto) :
      t=time()
      a=b=0
      while a>=0 :
        a=texto.find("<",b)
        if a>=0 :
           b=texto.find(">",a)
           texto=texto[:a]+texto[b+1:]
           b-=b-a
      print time()-t
      return texto
    

    Esta opción es similar a la anterior, pero no empieza a buscar desde el principio, sino donde lo había dejado.

  • Opción 3:
    from time import time
    def eliminaTags3(texto) :
      t=time()
      s=""
      a=b=0
      while a>=0 :
        a=texto.find("<",b)
        if a>=0 :
           s+=texto[b:a]
           b=texto.find(">",a)+1
      if b : s+=texto[b:]
      if s: texto=s
      print time()-t
      return texto
    

    Esta opción crea dos cadenas nuevas y elimina una antigua y una nueva. Según la implementación, el "s+=" podría incluso reutilizar el viejo objeto, lo que supondría reducir aún más los objetos creados y destruídos.

    Las cadenas generadas son más cortas que en el ejemplo anterior. La ocupación de memoria es, aproximadamente, el doble, porque mantenemos la cadena original hasta terminar de procesarla.

    Además, la búsqueda en la cadena original es incremental y no se empieza desde el principio en cada pasada. La importancia de este hecho crece a medida que lo hace la longitud de la cadena y el número de tags presentes en ella.

  • Opción 4:
    from time import time
    from string import join,find
    def eliminaTags4(texto) :
      t=time()
      s=[]
      a=b=0
      while a>=0 :
        #a=find(texto,"<",b)       # Esta operación es lenta
        a=texto.find("<",b)
        if a>=0 :
           s.append(texto[b:a])
           #b=find(texto,">",a)+1  # Esta operación es lenta
           b=texto.find(">",a)+1
      if b : s.append(texto[b:])
      if s: texto=join(s,"")        # Esta operación es muy rápida
      print time()-t
      return texto
    

    Esta rutina es más rápida. Resulta extraño que el "find" del módulo "string" sea más lento que el nativo.

  • Opción 5:
    from time import time
    from cStringIO import StringIO
    def eliminaTags5(texto) :
      t=time()
      s=StringIO()
      a=b=0
      while a>=0 :
        a=texto.find("<",b)
        if a>=0 :
           s.write(texto[b:a])
           b=texto.find(">",a)+1
      if b : s.write(texto[b:])
      if s.tell(): texto=s.getvalue()
      print time()-t
      return texto
    
Opción 1Opción 2Opción 3Opción 4Opción 5
4925 bytes100%--325%----
12058 bytes27%49%145%167%165%
23906 bytes8%20%63%91%86%
59049 bytes1%2%17%36%36%

Se observa claramente que la tercera opción es mucho más rápida, y que escala bastante mejor con el tamaño de la cadena. De hecho la primera opción tiene un comportamiento cuadrático, mientras que la tercera es aproximadamente lineal.

La cuarta opción es la más rápida para cadenas largas, y su ventaja respecto a la 3 crece a medida que lo hace la cadena. Para cadenas cortas, las opciones 3 y 4 están prácticamente empatadas, destacándose ligeramente la opción 3.



Python Zope ©2003 jcea@jcea.es

Más información sobre los OpenBadges

Donación BitCoin: 19niBN42ac2pqDQFx6GJZxry2JQSFvwAfS