Решение с использованием простой машины состояний (детерминированного конечного автомата) было написано "в лоб" на Delphi, затем я его, как сумел, почти напрямую перевёл на Python, так что код громоздкий, явно не pythonic и производительность может страдать оттого, что я не использую какие-то встроенные штучки и не особо знаю, что влияет на производительность Python. Например, время сократилось с 41 до 33 секунд, когда я заменил выделение символа
for i in range(len(line)):
ch = line[i]
на
for ch in line:
Для файла из 10 миллионов строк по 9 случайных символов (110 мегабайт), принадлежащих указанным множествам, нативный (Delphi) код под Windows на Celeron 2.8 ГГц затрачивает около 4-5 секунд (3-4 секунды на загрузку данных с HDD и около секунды на саму обработку). Данный код (Python 3.6) тратит на всё 33 секунды (из них 11 сек. на загрузку файла, если просто прочитать все строки и ничего не делать).
Код проходит по каждой строке, считая количество больших, малых букв и цифр и прерывает обработку строки, если какой-либо из счётчиков превышает предел (3) (условия 2).
state - это текущее состояние, обозначает, какого типа символ обрабатывался ранее. 0 - неопределённо, 1 - цифра, 2 - заглавная, 3 - маленькая буква.
Если state не меняется, то проверяется длина серии seriescount из символов текущего типа (условия 1)
Если state меняется с 2 на 3 или наоборот, то проверяется, не был ли прошлый символ копией текущего в другом регистре (условие 3).
def dellines():
infile = open("d:\m1.txt", "r")
outfile = open("d:\m2.txt", "w")
for line in infile:
seriescnt = 0
bigcnt = 0
smallcnt = 0
digitcnt = 0
state = 0
for ch in line:
if (ch >= "0") and (ch <= "9"):
if (state == 1):
seriescnt += 1
if (seriescnt > 2):
state = 0
break
else:
seriescnt = 1
digitcnt += 1
if (digitcnt > 3):
state = 0
break
state = 1
elif (ch >= "A") and (ch <= "Z"):
if (state == 3):
if (ord(lastch) == ord(ch) + 32):
state = 0
break
if (state == 2):
seriescnt += 1
if (seriescnt > 2):
state = 0
break
else:
seriescnt = 1
bigcnt += 1
if (bigcnt > 3):
state = 0
break
lastch = ch
state = 2
elif (ch >= "a") and (ch <= "z"):
if (state == 2):
if (ord(lastch) == ord(ch) - 32):
state = 0
break
if (state == 3):
seriescnt += 1
if (seriescnt > 2):
state = 0
break
else:
seriescnt = 1
smallcnt += 1
if (smallcnt > 3):
state = 0
break
lastch = ch
state = 3
if (state):
outfile.write(line)
outfile.close()
infile.close()
start = time.time()
dellines()
end = time.time()
print(end - start)