Pythonのタブストップを意識しLEN()とパディング機能
質問
PythonのLEN()とstring.ljustなどのパディング機能()彼らは、他の単一幅の文字のような「\ t」の治療、すなわち認識TABSTOPされていない、とのラウンドタブストップの最も近い倍数までlenはありません。 例:
len('Bear\tnecessities\t')
(即ち4+(8-4)+11+(8-3))の代わりに24の17であります
と私はまた、機能pad_with_tabs(s)
をしたいと、このような
pad_with_tabs('Bear', 15) = 'Bear\t\t'
コンパクトさと読みやすさ第一、効率第二 - これらの簡単な実装を探しています。 これは、基本的なしかし、刺激性の問題です。 @gnibbler - あなたはそれが言っていたとしても、純粋にPython的解決策を示すことができる20倍の効率の低い
?確かにあなたは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)である場合の特殊ケース無し
誰もがより良いLENを表示することができます()とpad_with_tabs()関数?
解決
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
だけでも、タブに分割するには時間がかかります。あなたはまだタブストップに分割し、パッド上で各項目を反復処理する必要があると思います。
他のヒント
私はgnibblerのが最もprectical例のために最善であると信じています。しかし、いずれにせよ、ここにナイーブである(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
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: