2012-06-13 3 views
4

У меня есть файл, содержащий некоторые строки кода, за которым следует шаблон строки. Мне нужно написать все перед строкой, содержащей шаблон строки в файле один и все после шаблона строки в файле два:Как разбить один файл на два файла с помощью Python?

например. (Файл-содержание)

  • codeline 1
  • codeline 2
  • Строка шаблона
  • codeline 3

Вывод должен быть один файл с codeline 1, codeline 2 и подать два с codeline 3.

Я знаком с написанием файлов, но, к сожалению, я не знаю, как определить контент до и после e string pattern.

+0

Не могли бы вы привести пример шаблона строки и codeline используется? - Также это файл .csv или обычный файл .txt? – tabchas

ответ

9

Если входной файл помещается в память, самым простым решением является использование str.partition():

with open("inputfile") as f: 
    contents1, sentinel, contents2 = f.read().partition("Sentinel text\n") 
with open("outputfile1", "w") as f: 
    f.write(contents1) 
with open("outputfile2", "w") as f: 
    f.write(contents2) 

Это предполагает, что вы знаете точный текст линии, разделяющей две части.

+2

+1. Это действительно приятное, чистое, читаемое решение, если оно подходит в памяти. –

+0

+1 мой любимый, предпочитайте его по моему собственному решению, если ему дано такое же предостережение относительно установки в памяти – Levon

2

Наивный пример (который не загружает файл в память, как Свен):

with open('file', 'r') as r: 
    with open('file1', 'w') as f: 
     for line in r: 
      if line == 'string pattern\n': 
       break 
      f.write(line) 
    with open('file2', 'w') as f: 
     for line in r: 
      f.write(line) 

Это предполагает, что 'string pattern' происходит один раз в входном файле.

Если шаблон не является фиксированной строкой, вы можете использовать модуль re.

+2

Используйте инструкцию 'with', где открываются файлы. –

+1

@Lattyware это пример _naive_ :) Кроме того, в этом конкретном случае сложнее обычного адаптировать код к использованию 'with'. –

+2

И? 'with' - лучшая практика. Нет причин не использовать его. Идея о том, что ее сложно изменить просто, неверна - с ней проще использовать и обеспечивает закрытие файлов, даже на исключениях - то, что ваш код даже не пытается на данный момент. –

2

Более эффективный ответ, который будет работать с большими файлами и потребляют ограниченный объем памяти ..

inp = open('inputfile') 
out = open('outfile1', 'w') 
for line in inp: 
    if line == "Sentinel text\n": 
    out.close() 
    out = open('outfile2', 'w') 
    else: 
    out.write(line) 
out.close() 
inp.close() 
+2

Используйте инструкцию 'with', где открываются файлы. –

1

Вам нужно что-то вроде:

def test_pattern(x): 
    if x.startswith('abc'): # replace this with some exact test 
     return True 
    return False 

found = False 
out = open('outfile1', 'w') 
for line in open('inputfile'): 
    if not found and test_pattern(line): 
     found = True 
     out.close() 
     out = open('outfile2', 'w') 
    out.write(line) 
out.close() 

заменить линию StartsWith с тестом, который работает с вашим шаблоном (с использованием сопоставления шаблонов из re, если необходимо, но все, что найдет линия devider).

+0

Это приведет к 'NameError' для' true' или 'false'. Просто используйте 'return x.startswith ('abc')' вместо оператора 'if'. –

+2

Используйте инструкцию 'with', где открываются файлы. –

+2

@Sven: спасибо, что заметили опечатки. IMHO oneliner неуместен, если вы еще не знаете точно, как тестировать, это был просто легко расширяемый пример, когда провал был ложным. Если тест становится многострочным с другими операциями if, например. найдите первые 2 символа, затем разделите на '|' и проверьте следующие два символа, тогда это легче адаптироваться. – Anthon

3
with open('data.txt') as inf, open('out1.txt','w') as of1, open('out2.txt','w') as of2: 
    outf = of1 
    for line in inf: 
     if 'string pattern' in line: 
      outf = of2 
      continue # prevent output of the line with "string pattern" 
     outf.write(line) 

будет работать с большими файлами, так как он работает по строкам. Предполагается, что string pattern происходит только один раз во входном файле. Мне нравится str.partition() подход лучше если весь файл помещается в память (которая не может быть проблемой)

Использование with гарантирует, что файлы автоматически закрываются, когда вы сделали, или исключение встречается.

+1

Закрыть, но я верю, что ваш код приведет к появлению «string pattern» в 'outf2', когда в вопросе будет указано, что« string pattern »должен исчезнуть с выхода. В этом случае просто добавьте 'continue' в качестве следующей строки после' outf = outf2', и он должен работать. – robru

+0

@Robru Я упомянул об использовании 'continue', чтобы заставить' string pattern' исчезнуть, но я думаю, что я должен был внимательно прочитать вопрос :-) .. Я обновлю свое решение, спасибо. – Levon

5

Этот подход похож на Lev's, но использует itertools, потому что это весело.

dont_break = lambda l: l.strip() != 'string_pattern' 

with open('input') as source: 
    with open('out_1', 'w') as out1: 
     out1.writelines(itertools.takewhile(dont_break, source)) 
    with open('out_2', 'w') as out2: 
     out2.writelines(source) 

Вы можете заменить функцию dont_break регулярным выражением или чем-либо еще, если это необходимо.

+2

Это, пожалуй, лучшее решение для файлов, которые не помещаются в памяти. Itertools означает, что петли сделаны C-side, что означает, что они будут быстрее (что может иметь значение, учитывая большое количество строк, которые можно было бы ожидать там, где имеет значение память). Я хотел бы отметить, что если вы собираетесь отдельно определить лямбду, вы можете также использовать инструкцию 'def'. –

+0

+1 для развлечения. –

2

не более трех линий:

with open('infile') as fp, open('of1','w') as of1, open('of2','w') as of2: 
    of1.writelines(iter(fp.readline, sentinel)) 
    of2.writelines(fp) 
+0

Хорошая точка! Я всегда забываю об этой форме 'iter'. Конечно, он работает только для точных известных часовых, а не для регулярных выражений или чего-то подобного. – Dougal

Смежные вопросы