Frage

Pythons len () und padding-Funktionen wie string.ljust () nicht tabstop-aware, dh sie behandeln ‚\ t‘ wie jede andere einfachbreiten Charakter und nicht rund len bis zum nächsten Vielfachen von tabstop . Beispiel:

len('Bear\tnecessities\t')

17 statt 24 (d 4+ (8-4) +11+ (8-3))

und sagen, ich will auch eine Funktion pad_with_tabs(s), so dass

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

Suchen Sie eine einfache Implementierungen dieser - Kompaktheit und Lesbarkeit erste, Effizienz Sekunde. Dies ist eine einfache, aber irritierende Frage. @gnibbler - zeigen Sie eine rein Pythonic Lösung, auch wenn es sagen ist 20x weniger effizient

?

Sicher könnte man konvertieren hin und her str.expandtabs (TabWidth) verwenden, aber das ist klobig. Importieren von Mathe TABWIDTH * int( math.ceil(len(s)*1.0/TABWIDTH) ) zu bekommen scheint auch, wie massiv übertrieben.

Ich kann nichts mehr elegant als die folgenden verwalten:

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

und da Python-Strings sind unveränderlich und es sei denn, wir wollen Affen-Patch unsere Funktion in String-Modul, um es als eine Methode hinzuzufügen, müssen wir auch auf das Ergebnis der Funktion zuweisen:

s = pad_with_tabs(s, ...)

Insbesondere kann ich nicht sauber Ansätze erhält mit Liste Verständnis oder string.join (...)

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

, ohne die Sonderfälle-Gehäuse in dem Len (n) = maxlen bereits.

Kann mir jemand zeigen bessere len () und pad_with_tabs () -Funktionen?

War es hilfreich?

Lösung

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)

Warum habe ich verwenden expandtabs()?
Nun, es ist schnell

$ 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

Alles, was iteriert über die Zeichenfolge langsamer sein wird, weil nur die Iteration ~ 4 mal langsamer als expandtabs, auch wenn Sie nichts tun, in der Schleife.

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

Auch nur Splitting auf Registerkarten dauert länger. Sie würden nach wie vor müssen Iterierte über die Spaltung und Pad jedes Element der tabstop

Andere Tipps

Ich glaube, gnibbler die ist die beste für die meisten prectical Fälle. Aber wie auch immer, hier ist ein naive (ohne CR Buchhaltung, LF usw.) Lösung, die die Länge der Zeichenfolge zu berechnen, ohne erweiterte Kopie zu erstellen:

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

Wahrscheinlich könnte es für einige große Strings oder sogar Speicher abgebildeten Dateien nützlich sein. Und hier ist padding Funktion ein wenig optimiert:

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) ) ist in der Tat eine massive Über töten; Sie können das gleiche Ergebnis viel einfacher zu bekommen. Für positive i und n, zu verwenden:

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

Dieses Verfahren funktioniert in fast jede Sprache, die ich je benutzt habe, nach entsprechender Übersetzung.

Dann können Sie tun next_pos = round_up_positive_int(len(s), TABWIDTH)

Für eine leichte Erhöhung der Eleganz des Codes, anstelle von

while(s_len < maxlen):

verwenden diese:

while s_len < maxlen:
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top