Pregunta

len

de Python () y funciones de relleno como string.ljust () no se TabStop-consciente, es decir, que tratan a '\ t' como cualquier otro carácter ancho simple, y no len ronda hasta el múltiplo más cercano de tabstop . Ejemplo:

len('Bear\tnecessities\t')

es 17 en lugar de 24 (es decir 4+ (8-4) +11+ (8-3))

y decir también quiero una función tal que pad_with_tabs(s)

pad_with_tabs('Bear', 15) = 'Bear\t\t'

Búsqueda de implementaciones sencillas de éstas - compacidad y facilidad de lectura primero, segundo la eficiencia. Esta es una pregunta básica pero irritante. @gnibbler - se puede mostrar una solución puramente Pythonic, incluso si es decir 20 veces menos eficiente

?

Claro que podría convertir un lado a otro usando str.expandtabs (TABWIDTH), pero eso es torpe. Importación de matemáticas para obtener TABWIDTH * int( math.ceil(len(s)*1.0/TABWIDTH) ) también parece un exceso masivo.

No podía manejar nada más elegante que lo siguiente:

TABWIDTH = 8

def pad_with_tabs(s,maxlen):
  s_len = len(s)
  while s_len < maxlen:
    s += '\t'
    s_len += TABWIDTH - (s_len % TABWIDTH)
  return s

y desde cadenas de Python son inmutables y si no queremos mono-parche de nuestra función en el módulo de cadena para agregarlo como un método, también hay que asignar al resultado de la función:

s = pad_with_tabs(s, ...)

En particular, no pude conseguir enfoques limpios utilizando la lista-comprensión o string.join (...)

''.join([s, '\t' * ntabs])

sin-especial carcasa los casos en los que len (s) es = maxlen ya.

¿Alguien puede mostrar mejor len () y pad_with_tabs () funciones?

¿Fue útil?

Solución

TABWIDTH=8
def my_len(s):
    return len(s.expandtabs(TABWIDTH))

def pad_with_tabs(s,maxlen):
    return s+"\t"*((maxlen-len(s)-1)/TABWIDTH+1)

¿Por qué utilizo expandtabs()?
Bueno, es rápido

$ python -m timeit '"Bear\tnecessities\t".expandtabs()'
1000000 loops, best of 3: 0.602 usec per loop
$ python -m timeit 'for c in "Bear\tnecessities\t":pass'
100000 loops, best of 3: 2.32 usec per loop
$ python -m timeit '[c for c in "Bear\tnecessities\t"]'
100000 loops, best of 3: 4.17 usec per loop
$ python -m timeit 'map(None,"Bear\tnecessities\t")'
100000 loops, best of 3: 2.25 usec per loop

Cualquier cosa que itera sobre la cadena va a ser más lenta, ya que sólo la iteración es ~ 4 veces más lento que expandtabs incluso cuando no hace nada en el bucle.

$ python -m timeit '"Bear\tnecessities\t".split("\t")'
1000000 loops, best of 3: 0.868 usec per loop

Aunque sólo sea dividir en las pestañas lleva más tiempo. Todavía había necesidad de iterar sobre la separación y la almohadilla de cada elemento a la tabstop

Otros consejos

Creo gnibbler es el mejor para la mayoría de los casos prectical. Pero de todos modos, aquí es una ingenua (sin tener en cuenta CR, LF, etc) solución para calcular la longitud de la cuerda sin crear una copia ampliada:

def tab_aware_len(s, tabstop=8):
    pos = -1
    extra_length = 0
    while True:
        pos = s.find('\t', pos+1)
        if pos<0:
            return len(s) + extra_length
        extra_length += tabstop - (pos+extra_length) % tabstop - 1

Probablemente podría ser útil para algunas grandes cadenas o incluso archivos de memoria asignada. Y aquí es función de relleno un poco optimizado:

def pad_with_tabs(s, max_len, tabstop=8):
    length = tab_aware_len(s, tabstop)
    if length<max_len:
        s += '\t' * ((max_len-1)//tabstop + 1 - length//tabstop)
    return s

TABWIDTH * int( math.ceil(len(s)*1.0/TABWIDTH) ) es de hecho un enorme exceso de matanza; se puede obtener el mismo resultado mucho más simple. Para i positivo y n, utilice:

def round_up_positive_int(i, n):
    return ((i + n - 1) // n) * n

Este procedimiento funciona en casi cualquier lenguaje que he utilizado, después de la traducción apropiada.

A continuación, puede hacer next_pos = round_up_positive_int(len(s), TABWIDTH)

Para un ligero aumento en la elegancia de su código, en lugar de

while(s_len < maxlen):

utilizar esto:

while s_len < maxlen:
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top