Я использую python 3,6 - 3,8.
Я пытаюсь заменить любой экземпляр одной новой строки на один пробел в тексте, прочитанном из файла. Моя цель - сжать абзацы в одну строку текста для повторного переноса на textwrap
. Поскольку textwrap
работает только с одним абзацем, мне нужен простой способ обнаружить / выделить абзацы, и сжатие их в одну строку текста представляется наиболее целесообразным. Чтобы это работало, любой экземпляр двух или более символов новой строки в последовательности определяет границу абзаца и должен быть оставлен в покое.
Моя первая попытка была с утверждениями lookahead / lookbehind, чтобы настаивать на том, что заменяемый мной символ новой строки не будет ограниченный другими символами новой строки:
re.sub(r'(?<!\n)\n(?!\n)', ' ', input_text)
В большинстве случаев это прекрасно работает. Однако я быстро наткнулся на случай, когда у кого-то был разделитель абзацев, содержащий другие пробелы.
Это пример текста, начинающийся с короткого абзаца. \ N \ nЭтот второй абзац достаточно длинный, чтобы разделить на две строки, поэтому он содержит \ n одну новую строку в середине. \ n \ nЭтот третий абзац имеет необычный разделитель перед ним; символ новой строки, за которым следует \ na, а затем еще одна строка. Это особый случай, который необходимо обработать \ nhandled.
Мое утверждение tacti c для прогнозирования / просмотра здесь не сработает, потому что требуемый просмотр должен иметь неопределенную длину (может быть пробел) есть, может быть, нет), и это не разрешено.
# this is an error
re.sub(r'(?<!\n\s*)\n(?!\s*\n)', ' ', input_text)
Моя следующая попытка состояла в том, чтобы сделать это в два прохода, удаляя любые пробелы, не являющиеся символом новой строки, между символами новой строки, но я не могу найти регулярное выражение, которое сделает это прекрасно. Это работает, sortof, но сжимает любые вхождения более двух строк.
# this compresses "\n\n\n" or "\n\n \n" into "\n\n"
re.sub(r'(?<!\n)\n(?!\n)', ' ', re.sub(r'\n\s*\n', '\n\n', input_text))
Я бы хотел этого избежать, потому что лишние пустые строки между абзацами могут быть преднамеренными; они должны быть оставлены в покое.
Unicode-определение \s
не задает c, что недостаточно для того, чтобы я мог создать набор символов «все пробелы, кроме новых строк», поэтому я не могу что-то сделать вот так:
# this only works for ASCII
re.sub(r'(?<!\n)\n(?!\n)', ' ', re.sub(r'\n[ \t\r\f\v]*\n', '\n\n', input_text))
Для этого мне нужен способ express "\s
кроме \n
" для Unicode, и я не думаю, что он существует. Я попробовал [\s!\n]
на жаворонке и, как ни странно, кажется, что он делает правильные вещи в 3.6.5 и 3.8.0. Это, несмотря на тот факт, что !
не имеет документированного эффекта внутри набора символов для любой версии, и что в документации для re.escape()
прямо говорится, что с 3.7, !
больше не экранируется методом, поскольку это не так. особый характер.
# this appears to work, but the docs say it shouldn't
re.sub(r'(?<!\n)\n(?!\n)', ' ', re.sub(r'\n[\s!\n]\n', '\n\n', input_text))
Даже если это работает, я не хочу полагаться на поведение по понятным причинам. Вероятно, я должен сообщить об этом как об ошибке в коде или документации.
Если предположить, что последний не поддерживается, какой еще подход я пропускаю?