Регулярное выражение для удаления разрывов строк
Я полный новичок в Python, и я застрял в проблеме с регулярным выражением. Я пытаюсь удалить символ разрыва строки в конце каждой строки в текстовом файле, но только если он следует строчной букве, то есть [a-z]
. Если конец строки заканчивается строчной буквой, я хочу заменить символ разрыва строки/новой строки пробелом.
Это то, что у меня есть до сих пор:
import re
import sys
textout = open("output.txt","w")
textblock = open(sys.argv[1]).read()
textout.write(re.sub("[a-z]\z","[a-z] ", textblock, re.MULTILINE) )
textout.close()
Ответы
Ответ 1
Попробуйте
re.sub(r"(?<=[a-z])\r?\n"," ", textblock)
\Z
совпадает только в конце строки, после последней строки, так что это определенно не то, что вам нужно здесь. \Z
не распознается механизмом регулярного выражения Python.
(?<=[a-z])
является положительным утверждением lookbehind, который проверяет, является ли символ перед текущей позицией строчным символом ASCII. Только тогда двигатель регулярных выражений попытается сопоставить разрыв строки.
Также всегда используйте необработанные строки с регулярными выражениями. Делает обратную косую черту легче обрабатывать.
Ответ 2
Как альтернативный ответ, хотя он требует больше строк, я думаю, что следующее может быть более четким, поскольку регулярное выражение проще:
import re
import sys
with open(sys.argv[1]) as ifp:
with open("output.txt", "w") as ofp:
for line in ifp:
if re.search('[a-z]$',line):
ofp.write(line.rstrip("\n\r")+" ")
else:
ofp.write(line)
... и это позволяет избежать загрузки всего файла в строку. Если вы хотите использовать меньшее количество строк, но все же избегайте появления postive lookbehind, вы можете сделать:
import re
import sys
with open(sys.argv[1]) as ifp:
with open("output.txt", "w") as ofp:
for line in ifp:
ofp.write(re.sub('(?m)([a-z])[\r\n]+$','\\1 ',line))
Части этого регулярного выражения:
-
(?m)
[включить многострочное сопоставление]
-
([a-z])
[совпадение с одним строчным символом в качестве первой группы]
-
[\r\n]+
[совпадение с одним или несколькими символами возврата каретки или новой строки, для покрытия \n
, \r\n
и \r
]
-
$
[соответствует концу строки]
... и если это соответствует строке, строчная буква и окончание строки заменяются на \\1
, что будет буквой нижнего регистра, за которой следует пробел.
Ответ 3
моя точка зрения заключалась в том, что избежать использования положительного lookbehind может сделать код более удобочитаемым
OK. Хотя, лично, я не считаю это менее читаемым. Это вопрос вкуса.
В своем EDIT:
-
Во-первых, (? m) не требуется, так как для строки в ifp: выбирает одну строку за раз, и поэтому на конец каждой строки строки
-
Во-вторых, $, поскольку он помещен, не имеет полезности, потому что он всегда будет соответствовать концу строковой строки.
В любом случае, принимая вашу точку зрения, я нашел два способа избежать утверждения lookbehind:
with open(sys.argv[1]) as ifp:
with open("output.txt", "w") as ofp:
for line in ifp:
ante_newline,lower_last = re.match('(.*?([a-z])?$)',line).groups()
ofp.write(ante_newline+' ' if lower_last else line)
и
with open(sys.argv[1]) as ifp:
with open("output.txt", "w") as ofp:
for line in ifp:
ofp.write(line.strip('\r\n')+' ' if re.search('[a-z]$',line) else line)
второй лучше: только одна строка, простое совпадение с тестом, нет необходимости в группах(), естественно логике
EDIT: oh Я понимаю, что этот второй код - это просто ваш первый код, переписанный в одной строке, Longair