2013-09-20 4 views
4

im new для Python, для программирования в целом.удалить первый символ из каждой строки в текстовом файле

Я хочу удалить первый символ из каждой строки в текстовом файле и записать изменения обратно в файл. Например, у меня есть файл с 36 строками, а первый символ в каждой строке содержит символ или номер, и я хочу, чтобы он был удален.

Здесь я сделал небольшой код, но он не работает должным образом, он только дублирует все залоги. Любая помощь будет оценена заранее!

from sys import argv 

run, filename = argv 

f = open(filename, 'a+') 
f.seek(0) 
lines = f.readlines() 
for line in lines: 
    f.write(line[1:]) 
f.close() 
+1

Ваша цель - написать программу или удалить символы. Если последнее, то выполните: 'sed -i 's /^.//' filename.txt'. –

+0

Просто удалите символы. Кстати, это reg exp? Как использовать строку кода ur? – izdi

+0

Чтобы использовать решение Роба, вам нужно установить программное обеспечение '' sed'' – eyquem

ответ

6

Ваш код уже делает удалить первый символ. Я спас именно ваш код, как dupy.py и dupy.txt, а затем побежал python dupy.py dupy.txt, и результат:

from sys import argv 

run, filename = argv 

f = open(filename, 'a+') 
f.seek(0) 
lines = f.readlines() 
for line in lines: 
    f.write(line[1:]) 
f.close() 
rom sys import argv 
un, filename = argv 
= open(filename, 'a+') 
.seek(0) 
ines = f.readlines() 
or line in lines: 
    f.write(line[1:]) 
.close() 

Это не копирование целых строк; это копирование строк с их первым символом.


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

from sys import argv 

run, filename = argv 

f = open(filename) 
lines = f.readlines() 
f.close() 
f = open(filename, 'w') 
for line in lines: 
    f.write(line[1:]) 
f.close() 

Или, наоборот, записать новый файл, а затем переместить его поверх оригинала, когда вы сделали:

import os 
from sys import argv 

run, filename = argv 

fin = open(filename) 
fout = open(filename + '.tmp', 'w') 
lines = f.readlines() 
for line in lines: 
    fout.write(line[1:]) 
fout.close() 
fin.close() 
os.rename(filename + '.tmp', filename) 

(Обратите внимание, что эта версия не будет работать, как есть на Windows, но это проще, чем текущая версия кросс-платформенного;., если вам нужна Windows, я могу объяснить, как это сделать)


вы можете сделать код намного проще, более надежными и более эффективными Cient с помощью with заявления, зацикливание непосредственно над файлом вместо вызова readlines, и с помощью tempfile:

import tempfile 
from sys import argv 

run, filename = argv 

with open(filename) as fin, tempfile.NamedTemporaryFile(delete=False) as fout: 
    for line in fin: 
     fout.write(line[1:]) 
    os.rename(fout.name, filename) 

На большинстве платформ, это гарантирует «атомное запись» -когда ваш сценарий заканчивается, или даже если кто-то тянет подключится к середине запуска, файл будет либо заменен новой версией, либо нетронутым; нет никакого способа, которым это может закончиться на полпути, переписанным в неустранимый мусор.

Опять же эта версия не будет работать в Windows. Без большой работы нет способа реализовать этот алгоритм «write-temp-and-rename» в Windows. Но вы можете приблизиться только немного дополнительной работа:

with open(filename) as fin, tempfile.NamedTemporaryFile(delete=False) as fout: 
    for line in fin: 
     fout.write(line[1:]) 
    outname = fout.name 
os.remove(filename) 
os.rename(outname, filename) 

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

+0

Windows-совместимая версия вашего последнего решения будет состоять в том, чтобы использовать файл-подобный объект в памяти, а затем записать его потом. – Marcin

+0

@ Марцин: Нет, это совсем не эквивалентно; он не гарантированно является атомарным, что является целым рядом с идиомой write-temp-and-rename. Фактически, это не совсем так, как просто создание списка и вызов 'writelines', или даже использование первой версии. – abarnert

+0

** abarnert ** Спасибо за разъяснение! – izdi

3

Вы можете прочитать все строки в памяти, то восстановить файл,

from sys import argv 

run, filename = argv 

with open(filename, 'r') as f: 
    data = [i[1:] for i in f 
with open(filename, 'w') as f: 
    f.writelines(i+'\n' for i in data) # this is for linux. for win use \r\n 

или Вы можете создать другой файл и переместить данные из первого файла на вторую линию по линии. Затем Вы можете переименовать его, если вы хотите

from sys import argv 

run, filename = argv 

new_name = filename + '.tmp' 
with open(filename, 'r') as f_in, open(new_name, 'w') as f_out: 
    for line in f_in: 
     f_out.write(line[1:]) 

os.rename(new_name, filename) 
+0

Ваша последняя версия не работает в Windows. Это хорошо для примера, но вы должны упомянуть об этом. – abarnert

+0

Thx. Я добавлю это – oleg

3

На самом базовом, ваша проблема в том, что вам нужно seek обратно в начало файла после прочитать его полное содержимое в массив f. Поскольку вы делаете файл короче, вам также необходимо использовать truncate, чтобы отредактировать официальную длину файла после того, как вы закончите. Кроме того, открытый режим a+ (a для append) переопределяет seek и заставляет все записи перемещаться в конец файла. Так что ваш код должен выглядеть следующим образом:

import sys 

def main(argv): 
    filename = argv[1] 
    with open(filename, 'r+') as f: 
     lines = f.readlines() 
     f.seek(0) 
     for line in lines: 
      f.write(line[1:]) 
     f.truncate() 

if __name__ == '__main__': main(sys.argv) 

Это лучше, когда делают что-то вроде этого, чтобы записать изменения в файл новый, а затем переименовать его поверх старого файла, когда вы сделанный. Это приводит к тому, что обновление происходит «атомарно» - одновременный читатель видит либо старый файл, либо новый, а не какую-то извращенную комбинацию из двух. Это выглядит следующим образом:

import os 
import sys 
import tempfile 

def main(argv): 
    filename = argv[1] 
    with open(filename, 'r') as inf: 
     with tempfile.NamedTemporaryFile(dir=".", delete=False) as outf: 
      tname = outf.name 
      for line in inf: 
       outf.write(line[1:]) 
    os.rename(tname, filename) 

if __name__ == '__main__': main(sys.argv) 

(Примечание. Атомарно замена файла не работает на Windows, с помощью rename, вы должны os.remove старое название первого К сожалению, это не означает, есть небольшое окно (не каламбур) где одновременно читатель обнаружит, что файл не существует, насколько я знаю, нет никакого способа, чтобы избежать этого)

+0

. Ваша последняя версия не будет работать в Windows. Это хорошо для примера, особенно если OP не в Windows, но вы должны упомянуть об этом. – abarnert

+0

Я попробую это, мне нравится идея – izdi

2
import re 

with open(filename,'r+') as f: 
    modified = re.sub('^.','',f.read(),flags=re.MULTILINE) 
    f.seek(0,0) 
    f.write(modified) 

в шаблоне регулярного выражения:.. «начало строки»
^ означает
«Начало строки»с флагом re.MULTILINE означает

^. означает «только один символ в начале строки»

Начало линии является началом строки или любое положение после перевода строки (a newline is \n)
Итак, мы можем опасаться, что некоторые символы новой строки в таких последовательностях, как \n\n\n\n\n\n\n, могут совпадать с шаблоном регулярного выражения.
Но точка символизирует любой символ. ИСКЛЮЧАЕТ новую строку, тогда все новые строки не соответствуют этому шаблону регулярного выражения.

Во время чтения файла, вызванного f.read(), указатель файла доходит до конца файла.

f.seek(0,0) перемещает указатель файла обратно в начало файла

f.truncate() ставит новый EOF = конец файла в точке, где написание остановилось. Это необходимо, так как измененный текст короче исходного.
Сравните то, что он делает с кодом без этой линии

2

Чтобы быть оттачивает, я действительно не знаю, как хорошо/плохо идея вложенности with open(), но вы можете сделать что-то вроде этого.

with open(filename_you_reading_lines_FROM, 'r') as f0: 
    with open(filename_you_appending_modified_lines_TO, 'a') as f1: 
     for line in f0: 
      f1.write(line[1:]) 
+0

Вложение 'open 'не обязательно _bad_, но это редко необходимо, потому что вы можете просто поместить оба из них в один и тот же оператор' with', как и во многих других ответах размещен здесь. – abarnert

0

В то время казалось, некоторое обсуждение наилучшей практики и будет ли она работать на Windows, или нет, будучи новым для Python, я смог запустить первый пример, который работал и заставить его работать в моей Win среда, которая имеет Cygwin двоичные файлов в моих окружающей среде переменных путей и удалите первый 3 символа (которые были номера строк из файла образца):

import os 
from sys import argv 

run, filename = argv 

fin = open(filename) 
fout = open(filename + '.tmp', 'w') 
lines = fin.readlines() 
for line in lines: 
    fout.write(line[3:]) 
fout.close() 
fin.close() 

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

python c:\bin\remove1st3.py sampleCode.txt 
Смежные вопросы