Python的制表位感知LEN()和填充功能
题
Python的LEN()和填充功能,如string.ljust()不接受tab感知,即,它们对待“\ T”像任何其他单宽字符,并且不圆len个到制表位的最接近的倍数。 例如:
len('Bear\tnecessities\t')
是17而不是24(即4+(8-4)+11+(8-3))
和说我也希望有一个功能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中的字符串是不变的,除非我们想猴补丁我们的函数为string模块将其添加为一个方法,我们还必须分配给函数的结果:
s = pad_with_tabs(s, ...)
在我特别不能让使用列表理解或的string.join(...)清洁方法
''.join([s, '\t' * ntabs])
没有特殊壳体的情况下,LEN(s)为= MAXLEN已经
任何人都可以显示出更好的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: