2009-04-07 7 views
1

Я конвертирую код с другого языка на python. Этот код считывает довольно большой файл в строку, а затем манипулирует его индексирование массива как:Обработка строк в Python

str[i] = 'e' 

Это не работает непосредственно в питоне из-за струны быть неизменен. Каков предпочтительный способ сделать это в python?

Я видел функцию string.replace(), но возвращает копию строки, которая не кажется очень оптимальной, так как строка в этом случае является целым файлом.

+0

насколько велика строка/файл? – SilentGhost

+0

Вы всегда заменяете одну и ту же колонку или выполняете поиск и замену? – vartec

+0

Что заменяется, зависит от содержимого файла – Zitrax

ответ

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

Выглядит хорошо, но будет ли он работать с огромным файлом? – theycallmemorty

+0

@theycallmemorty: он потребляет вдвое больше памяти, чем C, но кроме этого, я не вижу причин, почему он не должен работать. –

+0

На самом деле, если сделано много таких манипуляций, лучше всего держать строки в виде списков символов. – 2009-04-07 12:43:04

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 ОС):

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 

Так ММАП немного быстрее, но ни один из предложенных решений не является особо отличается. Если вы видите огромную разницу, попробуйте использовать 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 используется диапазон(), который вызвал много накладных расходов. Я переключился на петли, и теперь производительность хорошая. – Zitrax

1

Другие ответили манипулирующую струну части вашего вопроса, но я думаю, что вы должны думать о том, будет ли лучше разобрать файл и изменить структуру данных, текст представляет собой весьма чем манипулирование текстом напрямую.