4

Python の len() と string.ljust() のようなパディング関数はタブストップを認識しません。つまり、'\t' を他の半角文字と同様に扱い、len を最も近いタブストップの倍数に切り上げません。例:

len('Bear\tnecessities\t')

24 ではなく 17 です (つまり、4+(8-4)+11+(8-3) )。

そして、私もpad_with_tabs(s)そのような関数が欲しいと言います

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

これらの単純な実装を探しています - コンパクトさと読みやすさを第一に、効率を第二に。これは基本的ですが、イライラする質問です。@gnibbler - たとえ20倍効率が悪いとしても、純粋にPythonicのソリューションを示すことができますか?

確かに str.expandtabs(TABWIDTH) を使用して前後に変換できますが、それは扱いにくいです。取得するために数学をインポートすることTABWIDTH * int( math.ceil(len(s)*1.0/TABWIDTH) )も、非常にやり過ぎのようです。

以下よりもエレガントなものを管理できませんでした。

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

また、Python 文字列は不変であるため、関数を文字列モジュールにモンキー パッチしてメソッドとして追加する場合を除き、関数の結果にも代入する必要があります。

s = pad_with_tabs(s, ...)

特に、リスト内包表記または string.join(...) を使用したクリーンなアプローチを取得できませんでした。

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

len(s) が < TABWIDTH の整数倍である場合、または len(s)>=maxlen である場合は、特別なケースを除きます。

誰でも len() と pad_with_tabs() 関数をもっとうまく表示できますか?

4

4 に答える 4

8
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)

なぜ使用したのexpandtabs()ですか?
まぁ速いです

$ 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

expandtabs文字列を反復するものはすべて遅くなります。ループ内で何もしない場合よりも、反復だけで最大 4 倍遅くなるためです。

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

タブを分割するだけでも時間がかかります。分割を反復処理し、各項目をタブストップに埋め込む必要があります

于 2009-11-17T02:34:14.603 に答える
1

ほとんどの実際のケースでは、ニブラーが最適だと思います。とにかく、展開されたコピーを作成せずに文字列の長さを計算する単純な (CR、LF などを考慮しない) ソリューションを次に示します。

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

おそらく、いくつかの巨大な文字列やメモリ マップされたファイルにも役立つ可能性があります。そして、ここに少し最適化されたパディング関数があります:

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
于 2009-11-17T14:46:06.490 に答える
0

TABWIDTH * int( math.ceil(len(s)*1.0/TABWIDTH) )確かに大規模なやり過ぎです。はるかに簡単に同じ結果を得ることができます。正iの とnの場合は、次を使用します。

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

この手順は、適切な翻訳を行った後、私が今まで使用したほぼすべての言語で機能します。

それからあなたはすることができますnext_pos = round_up_positive_int(len(s), TABWIDTH)

代わりに、コードのエレガンスをわずかに向上させるために

while(s_len < maxlen):

これを使って:

while s_len < maxlen:
于 2009-11-17T14:37:37.297 に答える