1

一部のコードを別の言語から Python に変換しています。そのコードは、かなり大きなファイルを文字列に読み取り、次のような配列のインデックス付けによって操作します。

str[i] = 'e'

文字列が不変であるため、これは Python では直接機能しません。python でこれを行うための推奨される方法は何ですか?

関数を見たstring.replace()ことがありますが、この場合の文字列はファイル全体であるため、最適とは言えない文字列のコピーを返します。

4

4 に答える 4

12

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 以外の OS では、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を使用して何が時間がかかっているかを確認してください。

于 2009-04-07T12:15:39.417 に答える
9
l = list(str)
l[i] = 'e'
str = ''.join(l)
于 2009-04-07T12:14:38.217 に答える
1

他の人があなたの質問の文字列操作部分に答えましたが、テキストを直接操作するよりも、ファイルを解析してテキストが表すデータ構造を変更する方が良いかどうかを考えるべきだと思います。

于 2009-04-07T14:57:50.337 に答える
0

試す:

sl = list(s)
sl[i] = 'e'
s = ''.join(sl)
于 2009-04-07T12:16:05.983 に答える