【发布时间】:2011-02-09 02:30:42
【问题描述】:
使用 Python,我需要每 64 个字符在字符串中插入一个换行符。在 Perl 中很简单:
s/(.{64})/$1\n/
如何在 Python 中使用正则表达式来做到这一点? 有没有更pythonic的方式来做到这一点?
【问题讨论】:
使用 Python,我需要每 64 个字符在字符串中插入一个换行符。在 Perl 中很简单:
s/(.{64})/$1\n/
如何在 Python 中使用正则表达式来做到这一点? 有没有更pythonic的方式来做到这一点?
【问题讨论】:
我会选择:
import textwrap
s = "0123456789"*100
print('\n'.join(textwrap.wrap(s, 64)))
【讨论】:
textwrap 可以感知空间,因此无法正确处理 "12345 "*100。
让@J.F. Sebastian 的solution 更进一步(这几乎犯罪!:-)):
import textwrap
s = "0123456789"*100
print textwrap.fill(s, 64)
看,马...没有正则表达式!因为如你所知...http://regex.info/blog/2006-09-15/247
感谢您向我们介绍textwrap 模块...虽然它从 2.3 开始就在 Python 中,但直到现在我才意识到它(是的,我会公开承认)!!
【讨论】:
textwrap 可以感知空间,因此无法正确处理 "12345 "*100。
itertools 有一个很好的函数 grouper 对此很有用,特别是如果您的最终切片少于 64 个字符并且您不希望切片错误:
def grouper(iterable, n, fillvalue=None):
"Collect data into fixed-length chunks or blocks"
# grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx
args = [iter(iterable)] * n
return izip_longest(fillvalue=fillvalue, *args)
这样使用:
big_string = <YOUR BIG STRING>
output = '\n'.join(''.join(chunk) for chunk in grouper(big_string, 64))
【讨论】:
与 Perl 中的相同,但使用反斜杠而不是用于访问组的美元:
s = "0123456789"*100 # test string
import re
print re.sub("(.{64})", "\\1\n", s, 0, re.DOTALL)
re.DOTALL 等价于 Perl 的 s/ 选项。
【讨论】:
s2="0123456789"*200 ,您的解决方案似乎被破坏了,only 恰好插入了 16 个 '\n' (在 Python 2.7.1 上)。有什么办法吗?
re.DOTALL)。由于我忘记了那个参数,所以 re.DOTALL(值 16)被用作替换的最大数量。
64?
"(.{%d})"%varname 似乎有点骇人听闻;一定有更好的办法。
没有正则表达式:
def insert_newlines(string, every=64):
lines = []
for i in xrange(0, len(string), every):
lines.append(string[i:i+every])
return '\n'.join(lines)
较短但可读性较差(imo):
def insert_newlines(string, every=64):
return '\n'.join(string[i:i+every] for i in xrange(0, len(string), every))
以上代码适用于 Python 2.x。对于 Python 3.x,您要使用 range 而不是 xrange:
def insert_newlines(string, every=64):
lines = []
for i in range(0, len(string), every):
lines.append(string[i:i+every])
return '\n'.join(lines)
def insert_newlines(string, every=64):
return '\n'.join(string[i:i+every] for i in range(0, len(string), every))
【讨论】:
timeit.timeit 表示执行 100000 次正则表达式解决方案需要 27.8 秒,而执行 100000 次较短的解决方案需要 4.45 秒)。
join 方法。
我建议以下方法:
"\n".join(re.findall("(?s).{,64}", s))[:-1]
这或多或少是利用 RE 引擎进行循环的非 RE 方法。
在我作为家庭服务器的一台非常慢的计算机上,这给出了:
$ python -m timeit -s 's="0123456789"*100; import re' '"\n".join(re.findall("(?s).{,64}", s))[:-1]'
10000 loops, best of 3: 130 usec per loop
AndiDog的方法:
$ python -m timeit -s "s='0123456789'*100; import re" 're.sub("(?s)(.{64})", r"\1\n", s)'
1000 loops, best of 3: 800 usec per loop
gurney alex 的第二个/Michael 的方法:
$ python -m timeit -s "s='0123456789'*100" '"\n".join(s[i:i+64] for i in xrange(0, len(s), 64))'
10000 loops, best of 3: 148 usec per loop
我不认为textwrap 方法对于问题的规范是正确的,所以我不会计时。
因为不正确而更改了答案(真丢脸!)
只是为了好玩,使用itertools的无RE方法。它在速度上排名第三,而且它不是 Pythonic(太 lispy):
"\n".join(
it.imap(
s.__getitem__,
it.imap(
slice,
xrange(0, len(s), 64),
xrange(64, len(s)+1, 64)
)
)
)
$ python -m timeit -s 's="0123456789"*100; import itertools as it' '"\n".join(it.imap(s.__getitem__, it.imap(slice, xrange(0, len(s), 64), xrange(64, len(s)+1, 64))))'
10000 loops, best of 3: 182 usec per loop
【讨论】:
很小,不太好:
"".join(s[i:i+64] + "\n" for i in xrange(0,len(s),64))
【讨论】: