Манипулирование строками в Python

1

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

str[i] = 'e'

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

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

  • 0
    насколько велика строка / файл?
  • 0
    Вы всегда заменяете один и тот же столбец, или вы выполняете поиск и замену?
Показать ещё 1 комментарий
Теги:
string
replace

4 ответа

9
Лучший ответ
l = list(str)
l[i] = 'e'
str = ''.join(l)
  • 0
    Выглядит хорошо, но будет ли работать с огромным файлом?
  • 0
    @theycallmemorty: он потребляет вдвое больше памяти, чем C, но кроме этого, я не вижу никаких причин, почему он не должен работать.
Показать ещё 13 комментариев
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

Здесь приведен быстрый тест script (вам нужно будет заменить dd чем-то другим для не-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

Итак, mmap немного быстрее, но ни одно из предлагаемых решений не отличается. Если вы видите огромную разницу, попробуйте использовать cProfile, чтобы узнать, что займет время.

  • 0
    Кажется, я помню, что mmap предназначен только для Linux, поэтому вы можете столкнуться с проблемами переносимости.
  • 0
    Нет, он работает в Unix и Windows ( docs.python.org/library/mmap.html ). Есть небольшие отличия API, но они не влияют на этот вариант использования. На самом деле большая разница в Windows: do_mmap 0.65700006485; do_array 1.0150001049; do_split 0.827999830246.
Показать ещё 2 комментария
1

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

0

Try:

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню