2009-04-07 24 views
1

他の言語のコードをPythonに変換しています。このコードは、文字列の中にかなり大きなファイルを読み込み、その後のような配列のインデックスで、それを操作する:Pythonの文字列操作

str[i] = 'e' 

これが原因文字列は不変であることにPythonで直接動作しません。これをPythonで行うための好ましい方法は何ですか?

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

あなたは array.arrayを使用することができ、UTF-8などの可変長テキストエンコーディングを使用していないと仮定すると、
+0

文字列/ファイルの大きさはどれくらいですか? – SilentGhost

+0

あなたは常に同じ列を置き換えるか、検索と置換を行いますか? – vartec

+0

置き換えられる内容はファイルの内容によって異なります – Zitrax

答えて

9
l = list(str) 
l[i] = 'e' 
str = ''.join(l) 
+0

素晴らしいと思われますが、それは巨大なファイルで動作しますか? – theycallmemorty

+0

@theycallmemorty:C言語の2倍のメモリを消費しますが、それ以外の理由では動作しません。 –

+0

実際、このような操作がたくさんある場合、おそらく文字列を文字のリストとして保持することが最善の方法です。 –

12

:あなたは、ファイルの内容を扱っているので、

>>> 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を使用して時間の流れを確認してみてください。

+0

私はmmapがLinuxのみであることを思い出しているので、移植性の問題に直面する可能性があります。 –

+0

いいえ、UnixとWindows(http://docs.python.org/library/mmap.html)で動作します。 APIには若干の違いがありますが、このユースケースには何も影響しません。実際にはWindowsの大きな違いは:do_mmap 0.65700006485; do_array 1.0150001049; do_split 0.827999830246。 –

+0

cProfileに関するヒントをありがとう、それは私に問題を指摘しました。 forループはrange()を使用したため、オーバーヘッドが大きくなりました。私はwhileループに切り替えて、今はパフォーマンスが良いです。 – Zitrax

0

試してみてください。他の人があなたの質問の文字列操作の一部に答えているが、私はあなたはファイルを解析し、テキストではなく表すデータ構造を変更した方がよいかどうかを考えるべきだと思い

sl = list(s) 
sl[i] = 'e' 
s = ''.join(sl) 
1

テキストを直接操作するよりも。