我正在将一些代码从另一种语言转换为 python。该代码将一个相当大的文件读入一个字符串,然后通过数组索引来操作它,例如:
str[i] = 'e'
由于字符串是不可变的,这不能直接在 python 中工作。在 python 中这样做的首选方法是什么?
我看过这个string.replace()
函数,但它返回的字符串副本听起来不是很理想,因为在这种情况下,字符串是一个完整的文件。
假设您没有使用 UTF-8 等可变长度文本编码,您可以使用array.array
:
>>> import array
>>> a = array.array('c', 'foo')
>>> a[1] = 'e'
>>> a
array('c', 'feo')
>>> a.tostring()
'feo'
但是由于您正在处理文件的内容,mmap
因此应该更有效:
>>> f = open('foo', 'r+')
>>> import mmap
>>> m = mmap.mmap(f.fileno(), 0)
>>> m[:]
'foo\n'
>>> m[1] = 'e'
>>> m[:]
'feo\n'
>>> exit()
% cat foo
feo
这是一个快速基准测试脚本(对于非 Unix 操作系统,您需要将 dd 替换为其他内容):
import os, time, array, mmap
def modify(s):
for i in xrange(len(s)):
s[i] = 'q'
def measure(func):
start = time.time()
func(open('foo', 'r+'))
print func.func_name, time.time() - start
def do_split(f):
l = list(f.read())
modify(l)
return ''.join(l)
def do_array(f):
a = array.array('c', f.read())
modify(a)
return a.tostring()
def do_mmap(f):
m = mmap.mmap(f.fileno(), 0)
modify(m)
os.system('dd if=/dev/random of=foo bs=1m count=5')
measure(do_mmap)
measure(do_array)
measure(do_split)
我在几年前的笔记本电脑上得到的输出符合我的直觉:
5+0 records in
5+0 records out
5242880 bytes transferred in 0.710966 secs (7374304 bytes/sec)
do_mmap 1.00865888596
do_array 1.09792494774
do_split 1.20163106918
所以 mmap 稍微快一点,但没有一个建议的解决方案特别不同。如果您看到了巨大的差异,请尝试使用cProfile来查看花费时间的原因。
l = list(str)
l[i] = 'e'
str = ''.join(l)
其他人已经回答了您问题的字符串操作部分,但我认为您应该考虑解析文件并修改文本表示的数据结构而不是直接操作文本是否会更好。
尝试:
sl = list(s)
sl[i] = 'e'
s = ''.join(sl)