簡體   English   中英

Python 正則表達式替換單個換行符並忽略兩個或多個換行符的序列

[英]Python regex to replace single newlines and ignore sequences of two or more newlines

我正在使用 python 3.6 到 3.8。

我正在嘗試用從文件讀取的文本中的單個空格替換單個換行符的任何實例。 我的目標是將段落壓縮成單行文本,以便通過textwrap重新換行。 由於textwrap僅適用於單個段落,我需要一種簡單的方法來檢測/描繪段落,並將它們壓縮成一行文本似乎是最方便的。 為了讓它起作用,任何兩個或更多換行符的實例都定義了一個段落邊界,應該單獨保留。

我的第一次嘗試是使用前瞻/后視斷言來堅持我替換的任何換行符都不受其他換行符的限制:

re.sub(r'(?<!\n)\n(?!\n)', ' ', input_text)

這在大多數情況下都很好用。 但是,我很快遇到了一個案例,有人的段落分隔符包含其他空格。

這是一些以一小段開頭的示例文本。\n\n第二段足夠長,可以分成多行,因此它在中間包含\n一個換行符。\n \n第三段之前有一個不尋常的分隔符; 一個換行符后跟一個空格,然后是另一個換行符。 這是一個需要處理\n的特殊情況。

我的前瞻/后視斷言策略在這里不起作用,因為所需的后視需要具有不確定的長度(可能有空格,也可能沒有),這是不允許的。

# 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))

我想避免這種情況,因為段落之間的額外空行可能是故意的; 他們應該一個人呆着。

\s的 unicode 定義不夠具體,無法構造“除換行符外的所有空格”的字符集,所以我不能這樣做:

# this only works for ASCII
re.sub(r'(?<!\n)\n(?!\n)', ' ', re.sub(r'\n[ \t\r\f\v]*\n', '\n\n', input_text))

為此,我需要一種方法來為 unicode 表達“ \s except \n ”,但我認為它不存在。 我嘗試[\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))

盡管它似乎有效,但出於顯而易見的原因,我不想依賴這種行為。 我可能應該將其報告為代碼或文檔中的錯誤。

假設不應該支持最后一個,我還缺少其他什么方法?

您可以捕獲出現的雙倍和更多換行符以在匹配時保留它們並匹配所有其他換行符:

import re
text = "This is some sample text beginning with a short paragraph.\n\nThis second paragraph is long enough to be split across lines, so it contains\na single newline in the middle.\n \nThis third paragraph has an unusual separator before it; a newline followed by\na space followed by another newline. It's a special case that needs to be\nhandled."
print( re.sub(r'([^\S\n]*\n(?:[^\S\n]*\n)+[^\S\n]*)|[^\S\n]*\n[^\S\n]*', lambda x: x.group(1) or ' ', text) )

請參閱Python 演示

細節

  • ([^\S\n]*\n(?:[^\S\n]*\n)+[^\S\n]*) - 第 1 組:除換行符、換行符之外的 0+ 個空格,然后出現 1 次或更多次(因此,至少匹配兩個換行符)出現 0+ 個空格而不是換行符和換行符,然后再次出現 0+ 個空格而不是換行符
  • | - 要么
  • [^\S\n]*\n[^\S\n]* - 換行符以外的 0+ 個空格,換行符和換行符以外的 0+ 個空格

替換為lambda x: x.group(1) or ' ' :如果第 1 組匹配,則不應進行替換,否則用空格替換。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM