Разделить один файл на несколько файлов на основе шаблона (разрез может возникать в строках)

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

входной_файл:

<?xml 1><blabla1> <blabla><blabla2><blabla> <blabla><blabla> <blabla><blabla3><blabla><blabla> <blabla><blabla><blabla><?xml 4> <blabla> <blabla><blabla><blabla> <blabla><?xml 2><blabla><blabla> 

Должен стать с шаблоном <?xml

Outfile1:

 <?xml 1><blabla1> <blabla><blabla2><blabla> <blabla><blabla> <blabla><blabla3><blabla><blabla> <blabla><blabla><blabla> 

Outfile2:

 <?xml 4> <blabla> <blabla><blabla><blabla> <blabla> 

Outfile3:

 <?xml 2><blabla><blabla> 

На самом деле скрипт perl в подтвержденном ответе здесь отлично подходит для моего небольшого примера. Но он генерирует ошибку для моих более крупных (около 6 ГБ) фактических файлов. Ошибка:

 panic: sv_setpvn called with negative strlen at /home/.../split.pl line 7, <> chunk 1. 

У меня нет прав для комментариев, поэтому я начал новую запись. И, наконец, решение Python было бы еще более оценено, так как я понимаю его лучше.

4 Solutions collect form web for “Разделить один файл на несколько файлов на основе шаблона (разрез может возникать в строках)”

Это выполняет разделение без чтения всего в ОЗУ:

 def files(): n = 0 while True: n += 1 yield open('/output/dir/%d.part' % n, 'w') pat = '<?xml' fs = files() outfile = next(fs) with open(filename) as infile: for line in infile: if pat not in line: outfile.write(line) else: items = line.split(pat) outfile.write(items[0]) for item in items[1:]: outfile = next(fs) outfile.write(pat + item) 

Предупреждение: это не работает, если ваш шаблон распространяется по нескольким строкам (то есть содержит «\ n»). Рассмотрим решение mmap, если это так.

Perl может анализировать большие файлы по строкам, а не разбивать весь файл на память. Вот короткий сценарий (с объяснением):

 perl -n -E 'if (/(.*)(<\?xml.*)/ ) { print $fh $1 if $1; open $fh, ">output." . ++$i; print $fh $2; } else { print $fh $_ }' in.txt 

perl -n : флаг -n будет циклически перебирать файл по строке (установка содержимого в $ _)

-E : выполнить следующий текст (Perl ожидает имя файла по умолчанию)

if (/(.*)(<\?xml.*) ) <?xml if (/(.*)(<\?xml.*) ) если строка соответствует <?xml разделите эту строку (используя регулярные выражения) на $ 1 и $ 2.

print $fh $1 if $1 Распечатайте начало строки в старом файле.

open $fh, ">output.". ++$i; Создайте новый дескриптор файла для записи.

print $fh $2 Распечатайте остальную часть строки в новом файле.

} else { print $fn $_ } Если строка не соответствует <?xml просто распечатайте ее в текущем дескрипторе файла.

Примечание: этот скрипт предполагает, что ваш входной файл начинается с <?xml .

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

Объекты, связанные с памятью, ведут себя как обе строки, и как объекты файлов. Однако, в отличие от обычных строковых объектов, они изменяемы. Вы можете использовать объекты mmap в большинстве мест, где ожидаются строки; например, вы можете использовать модуль re для поиска по файлу с отображением памяти. Поскольку они изменяемы, вы можете изменить один символ, выполнив obj[index] = 'a' или изменив подстроку, назначив срезу: obj[i1:i2] = '...' . Вы также можете читать и записывать данные, начиная с текущей позиции файла, и seek() через файл в разные позиции.

Ниже приведен краткий пример, показывающий, как найти каждое вхождение <?xml #> в файле. Вы можете написать куски к новым файлам, когда вы идете, но я не написал эту часть.

 import mmap import re # a regex to match the "xml" nodes r = re.compile(r'\<\?xml\s\d+\>') with open('so.txt','r+b') as f: mp = mmap.mmap(f.fileno(),0) for m in r.finditer(mp): # here you can start collecting the starting positions and # writing chunks to new files print m.start() 

просто разделите свои поисковые запросы

 for i,part in enumerate(my_xml_Text_string.split("<?xml")): if not part.strip():continue # make sure its not empty with open("file%d.xml"%i,"w") as f: #open a file to write to f.write("<?xml"+part) #write the content putting your search term back in 
Python - лучший язык программирования в мире.