Я могу сделать это до сортировки, но регулярные выражения не работают в несколько строк.
Ваше регулярное выражение в порядке. У вас нет многострочных . У вас есть одиночные строки:
for line in s.readlines():
file.readlines()
читает весь файл в память в виде списка строк. Затем вы выполняете итерации по каждой из этих строк , поэтому line
будет 'asd\n'
или 'qwe\n'
, а никогда 'qwe\nqwe\n'
.
Учитывая, что вы читаете все свои объединенные файлы в память, я предположу, что ваши файлы не такие большие. В этом случае было бы гораздо проще просто прочитать один из этих файлов в заданный объект, а затем просто проверить каждую строку другого файла, чтобы найти различия:
with open('a.txt', 'r') as file_a:
lines = set(file_a) # all lines, as a set, with newlines
new_in_b = []
with open('b.txt', 'r') as file_b:
for line in file_b:
if line in lines:
# present in both files, remove from `lines` to find extra lines in a
lines.remove(line)
else:
# extra line in b
new_in_b.append(line)
print('Lines in a missing from b')
for line in sorted(lines):
print(line.rstrip()) # remove the newline when printing.
print()
print('Lines in b missing from a')
for line in new_in_b:
print(line.rstrip()) # remove the newline when printing.
print()
Если вы хотите записать все эти данные в файл, вы можете просто объединить две последовательности и записать отсортированный список:
with open('c.txt', 'w') as file_c:
file_c.writelines(sorted(list(lines) + new_in_b))
Ваш подход, сначала сортировка строк, помещение их всех в файл, а затем сопоставление парных строк, также возможна. Все, что вам нужно сделать, это запомнить предыдущую строку . Вместе с текущей линией это пара. Обратите внимание, что вам не нужно регулярное выражение для этого , просто тест на равенство:
with open('c.txt', 'r') as file_c, open('output.txt', 'w') as outfile:
preceding = None
skip = False
for line in file_c:
if preceding and preceding == line:
# skip writing this line, but clear 'preceding' so we don't
# check the next line against it
preceding = None
else:
outfile.write(preceding)
preceding = line
# write out the last line
if preceding:
outfile.write(preceding)
Обратите внимание, что это никогда не читает весь файл в память! Итерация непосредственно над файлом дает вам отдельные строки, где файл читается кусками в буфер. Это очень эффективный метод обработки линий.
Вы также можете перебирать файл по две строки за раз, используя библиотеку itertools
для отключения итератора объекта файла:
with open('c.txt', 'r') as file_c, open('output.txt', 'w') as outfile:
iter1, iter2 = tee(file_c) # two iterators with shared source
line2 = next(iter2, None) # move second iterator ahead a line
# iterate over this and the next line, and add a counter
for i, (line1, line2) in enumerate(zip(iter1, iter2)):
if line1 != line2:
outfile.write(line1)
else:
# clear the last line so we don't try to write it out
# at the end
line2 = None
# write out the last line if it didn't match the preceding
if line2:
outfile.write(line2)
Третий подход - использовать itertools.groupby()
для группировки строк, которые равны между собой. Затем вы можете решить, что делать с этими группами:
from itertools import groupby
with open('c.txt', 'r') as file_c, open('output.txt', 'w') as outfile:
for line, group in groupby(file_c):
# group is an iterator of all the lines in c that are equal
# the same value is already in line, so all we need to do is
# *count* how many such lines there are:
count = sum(1 for line in group) # get an efficient count
if count == 1:
# line is unique, write it out
outfile.write(line)
Я предполагаю, что не имеет значения, если есть 2 или более копий одной и той же строки. Другими словами, вы не хотите сопряжение , вы хотите найти только уникальные линии (те, которые присутствуют только в a или b).
Если ваши файлы очень большие , но уже отсортированы , вы можете использовать метод сортировки слиянием, без необходимости объединять два файла в один вручную. Функция heapq.merge()
дает вам строки из нескольких файлов в отсортированном порядке, если входные данные отсортированы по отдельности. Используйте это вместе с groupby()
:
import heapq
from itertools import groupby
# files a.txt and b.txt are assumed to be sorted already
with open('a.txt', 'r') as file_a, open('b.txt', 'r') as file_b,\
open('output.txt', 'w') as outfile:
for line, group in groupby(heapq.merge(file_a, file_b)):
count = sum(1 for line in group)
if count == 1:
outfile.write(line)
Опять же, эти подходы только читают достаточно данных из каждого файла, чтобы заполнить буфер. Итератор heapq.merge()
одновременно хранит в памяти только две строки, как и groupby()
. Это позволяет обрабатывать файлы любого размера независимо от ограничений памяти.