如何替換/刪除新行(\n)?

如何替換/刪除新行(\n)?

我只能訪問busybox 1.27.2

我目前正在處理一本超過 50 萬個單字、超過 6,000 頁的字典(使用 Ghostscript 從 PDF 中提取並轉換為純文字)。位於一個20MB .txt文件中。最初,這本字典中的每個單字都有一個前導,->以便更容易搜尋單字。

我試圖實現的目標是讓它變得*nix友善。這意味著如果我這樣做: grep -e '->myfancyword' ./dictionary.txt.

我應該得到結果:

->fancyword: This is a very fancy word. *Definition going on for more than 6 lines*

這可以透過刪除所有換行符號輕鬆完成\n,這樣每個單字的所有定義都會在很長的一行上,這是可以的。我可以將所有內容替換\ntr -d '\n',然後得到該結果的輸出,sed 's/->/\n->/g'這樣我就可以在一行中得到所有單字的定義。即使是這麼大的文檔,也能在 5 秒內完成。

我幾乎得到了我想要的結果,但並不完美。我可以做到這一點grep -e '->word' ./dictionary.txt並獲得這個詞的完整定義。但它在外觀上並不完美。

我對輸出不滿意的原因是,原始 pdf 的格式是列印在A4頁面上,這意味著當出現長單字時,它會被截斷。像這樣:

例如

->word: This is a defini-
tion.

如果我使用先前的工作流程處理文件,我會得到:->word: This is a defini- tion.當 grep 所需的單字時。

到目前為止,我設法完成的是:

  1. 輸入
->firstword: This is a defini-
tion.
->secondword: This is a second defini-
tion.
  1. 應用 tr -d '\n' < ./dictionary.txt > ./dictionary2.txt

  2. 輸出是:

->firstword: This is a defini- tion. ->secondword: This is a second defini- tion.
  1. 跑:sed -e 's/->/\n->/g' ./dictionary2.txt

  2. 結束於:

輸出

->firstword: This is a defini- tion.
->secondword: This is a second defini- tion.

在執行第二步驟之前,我想刪除破折號和新行(-\n)以將所有切碎的行「連接」在一起。

所以,我的問題是:如何替換/刪除行尾包含破折號-和換行符號\n( ) 的特定字串?-\n

我喜歡得到的是:

輸出(請檢查破折號和空格 ( -) 是否已不存在)

->firstword: This is a definition.
->secondword: This is a second definition.

謝謝。

編輯:

這是 PDF 檔案的一頁:


     ->abigeato. (Del lat. abigeatus). 1. m. Am. Hurto de ganado.
     ->abigeo. (Del lat. abigeus). 1. m. Am. Ladrón de ganado.
     ->abigotado, da. 1. adj. bigotudo.
     ->abinar. 1. tr. rur. y vulg. Binar la tierra.
     ->abintestato. (De ab intestato). 1. m. Der. Procedimiento judicial sobre herencia y
   adjudicación de bienes de quien muere sin testar.
     ->abiogénesis. (De a-2, bio- y -génesis). 1. f. Producción hipotética de seres vivos par-
   tiendo de materia inerte. 2. f. Bioquím. síntesis abiótica.
     ->abiótico, ca. 1. adj. Biol. Se dice del medio en que no es posible la vida.  V. síntesis
   abiótica
     ->abipón, na. 1. adj. Se dice del individuo de un pueblo amerindio que habitaba cerca del
   Paraná. U. t. c. s. 2. adj. Perteneciente o relativo a los abipones. 3. m. Lengua de la familia
   guaicurú hablada por los abipones.
     ->abisagrar. 1. tr. Clavar o fijar bisagras en las puertas y sus marcos, o en otros objetos.
     ->abisal. (Del lat. abyssus). 1. adj. abismal (|| perteneciente al abismo). 2. adj. Se dice de
   las zonas del mar profundo que se extienden más allá del talud continental, y corresponden a
   profundidades mayores de 2000 m. 3. adj. Perteneciente o relativo a tales zonas.
     ->abiselar. 1. tr. biselar.
     ->abisinio, nia. 1. adj. Natural de Abisinia, hoy Etiopía. U. t. c. s. 2. adj. Perteneciente o re-
   lativo a este país de África. 3. m. Lengua abisinia.  V. rito abisinio
     ->abismado, da. (Del part. de abismar). 1. adj. Dicho de una persona, de su expresión, de
   su gesto, etc.: Ensimismados, reconcentrados. 2. adj. Heráld. Dicho de una pieza del escudo:
   Puesta en el abismo.
     ->abismal (1).  (Del ár. hisp. almismár, y este del ár. clás. mismar). 1. m. Cada uno de los
   clavos con que se fijaba en el asta el hierro de la lanza.abismal2. 1. adj. Perteneciente o re-
   lativo al abismo. 2. adj. Muy profundo, insondable, incomprensible.
     ->abismar. 1. tr. Hundir en un abismo. U. t. c. prnl. 2. tr. Confundir, abatir. U. t. c. prnl. 3.
   prnl. Entregarse del todo a la contemplación, al dolor, etc. 4. prnl. Am. sorprenderse (|| con-
   moverse con algo imprevisto o raro).
     ->abismático, ca. 1. adj. abismal2.
     ->abismo. (Quizá del lat. vulg. *abyssimus, der. de abyssus, y este del gr. , sin fondo). 1.
   m. Profundidad grande, imponente y peligrosa, como la de los mares, la de un tajo, la de una
   sima, etc. U. t. en sent. fig. Se sumió en el abismo de la desesperación. 2. m. infierno (|| lugar
   de castigo eterno). 3. m. Cosa inmensa, insondable o incomprensible. 4. m. Diferencia
   grande entre cosas, personas, ideas, sentimientos, etc. 5. m. Heráld. Punto o parte central
   del escudo. 6. m. Nic. Maldad, perdición, ruina moral.

這是我在使用 Ghostscript 完成提取後 grep 常規文本時得到的結果(僅使用 dos2unix 處理):


grep -e '->abiog' ./rae-dos2unix.txt
     ->abiogénesis. (De a-2, bio- y -génesis). 1. f. Producción hipotética de seres vivos par-

這是在文本上完成前面的步驟(1-4)時,當 grep 時我得到:


grep -e '->abiog' ./rae-una-linea.txt
->abiogénesis. (De a-2, bio- y -génesis). 1. f. Producción hipotética de seres vivos par-   tiendo de materia inerte. 2. f. Bioquím. síntesis abiótica.     

答案1

這在 Perl 中相當容易。 perl 的-0選項告訴它使用 NUL 字符而不是換行符作為輸入記錄分隔符,因此,除非輸入中有 NUL 字符,否則它將把整個輸入文件視為一條記錄。即使有 NUL 字符,它也會繼續處理後續記錄,與第一個記錄相同。

注意:這確實意味著整個輸入檔案必須適合記憶體 - 在具有 16GB 或更多 RAM 的現代系統上,這不太可能成為問題。在 RAM 不足但交換空間足夠的舊系統上,它仍然可以工作,但速度會慢得多。

$ cat input.txt
->firstword: This is a defini-
tion.
->secondword: This is a second defini-
tion.
$ perl -0 -p -e 's/-\s*\n//g' input.txt 
->firstword: This is a definition.
->secondword: This is a second definition.

這將刪除每個連字符序列,後面跟著零個或多個空白字元(\s,見下文),後面跟著換行符(\n)。

正規表示式的部分\s*用於匹配尾隨空白字符可能位於行尾 - 根據我的經驗,文字行具有尾隨空格是很常見的(並且它們很難被發現,因為它們是非打印字符,即不可見)。或者,使用*(零個或多個空間字元)或[ \t]*(零個或多個空格或製表符)或\h*(零個或多個水平的空白字元)而不是\s*.

man perlre

被視為空白的字符集是 Unicode 稱為“模式空白”的字符,即:

U+0009 CHARACTER TABULATION
U+000A LINE FEED
U+000B LINE TABULATION
U+000C FORM FEED
U+000D CARRIAGE RETURN
U+0020 SPACE
U+0085 NEXT LINE
U+200E LEFT-TO-RIGHT MARK
U+200F RIGHT-TO-LEFT MARK
U+2028 LINE SEPARATOR
U+2029 PARAGRAPH SEPARATOR

筆記:

  1. 字元-並不是唯一可能使用的「連字號」或「破折號」字元。維基百科有列出 unicode 的頁面連字符短跑人物。幸運的是,perl 具有良好的 unicode 處理功能,因此可以重寫單行程式碼以使用\p{Dash}(或\p{Pd}),而不是-匹配所有破折號類別字元:
$ perl -0 -p -e 's/\p{Dash}\h*\n//g' input.txt 
->firstword: This is a definition.
->secondword: This is a second definition.

然而,這會將破折號視為連字符(因此將刪除行尾的破折號,與連字符相同)...並且使用破折號代替括號並不罕見。如果您不介意有關“連字符”被棄用的警告訊息,您可以使用\p{Hyphen}而不是。\p{Dash}或者您可以使用括號表達式,其中僅包含您想要視為連字符的 unicode 代碼點 - 例如

    perl -0 -p -e 's/[\N{U+002D}\N{U+00AD}\N{U+2010}\N{U+2011}]\h*\n//g' input.txt
  1. 我建議不要讓每個單字的定義都以 開頭->。這將使使用 grep 搜尋單字變得不必要的尷尬 - 搜尋字串必須用引號引起來(因為>,shell 使用它進行重定向)並在前面加上--(因為-,否則 grep 會將您的搜尋模式視為如果你的意思是它們是選項)。例如,您將無法僅執行以下操作:

     grep ^firstword: dictionary.txt
    

    相反,你必須這樣做:

     grep -- '^->firstword:' dictionary.txt
    

為了更好的例子,我從你的圖像中提取了文本tesseract-ocr並透過 perl one-liner 的一個版本運行它,該版本還刪除所有後面沒有跟隨的換行符->

$ cat input2.txt 
->abigeato. (Del lat. abigeatus). 1. m. Am. Hurto de ganado.
->abigeo. (Del lat. abigeus). 1. m. Am. Ladrén de ganado.
->abigotado, da. 1. adj. bigotudo.
->abinar. 1. tr. rur. y vulg. Binar la tierra.
->abintestato. (De ab intestato). 1. m. Der. Procedimiento judicial sobre herencia y
adjudicacion de bienes de quien muere sin testar.
Eiiftiénesis. (De a-2, bio- y -génesis). 1. f. Produccién hipotética de seres vivos par-
tiendo de materia inerte. 2. f. Bioquim. sintesis abistica,
->abidtico, ca. 1. adj. Biol. Se dice del medio en que no es posible la vida. V. sintesis
abidtica
->abipon, na. 1. adj. Se dice del individuo de un pueblo amerindio que habitaba cerca del
Parana. U. t.c. s. 2. adj. Perteneciente o relativo a los abipones. 3. m. Lengua de la familia
guaicurt hablada por los abipones.
->abisagrar. 1. tr. Clavar o fijar bisagras en las puertas y sus marcos, 0 en otros objetos.
->abisal. (Del lat. abyssus). 1. adj. abismal (|| perteneciente al abismo). 2. adj. Se dice de
las zonas del mar profundo que se extienden mas alla del talud continental, y corresponden a
$ perl -0 -p -e 's/[\N{U+002D}\N{U+00AD}\N{U+2010}\N{U+2011}]\h*\n//g; s/\n+(?!->)//g' input2.txt
->abigeato. (Del lat. abigeatus). 1. m. Am. Hurto de ganado.
->abigeo. (Del lat. abigeus). 1. m. Am. Ladrén de ganado.
->abigotado, da. 1. adj. bigotudo.
->abinar. 1. tr. rur. y vulg. Binar la tierra.
->abintestato. (De ab intestato). 1. m. Der. Procedimiento judicial sobre herencia yadjudicacion de bienes de quien muere sin testar.Eiiftiénesis. (De a-2, bio- y -génesis). 1. f. Produccién hipotética de seres vivos partiendo de materia inerte. 2. f. Bioquim. sintesis abistica,
->abidtico, ca. 1. adj. Biol. Se dice del medio en que no es posible la vida. V. sintesisabidtica
->abipon, na. 1. adj. Se dice del individuo de un pueblo amerindio que habitaba cerca delParana. U. t.c. s. 2. adj. Perteneciente o relativo a los abipones. 3. m. Lengua de la familiaguaicurt hablada por los abipones.
->abisagrar. 1. tr. Clavar o fijar bisagras en las puertas y sus marcos, 0 en otros objetos.
->abisal. (Del lat. abyssus). 1. adj. abismal (|| perteneciente al abismo). 2. adj. Se dice delas zonas del mar profundo que se extienden mas alla del talud continental, y corresponden a

我仍然建議->從最終輸出檔案中刪除該序列。它在處理文字時是一個有用的標記,但之後會出現問題。


@zevzek 的評論解決了“使用大量 RAM”的問題。不要使用 NUL 作為輸入記錄分隔符,而是使用->as 分隔符。這使得 perl 腳本一次只讀取一個單字定義,而不是一次讀取整個檔案。這將使它在處理非常大的輸入檔案時運行得更快,因為它不會使用所有可用的 RAM 並導致系統交換。

腳本還需要進行其他更改,因為我們現在正在處理標記開始一個新詞的定義為結尾前面的定義。具體來說,我們現在需要:

  • 將命令列選項-p(始終輸出當前記錄)變更為-n(僅在我們指定時輸出當前記錄)。
  • 刪除行尾字元(perl 的chomp()函數就是這樣做的)
  • 檢查輸入記錄是否為空或僅包含空格,因為現在將有一個假想第一個實際記錄“abigeato”之前有空記錄,我們不想將其打印出來。 (為什麼突然出現一個想像中的空記錄?因為->now表示一筆記錄的結束,而不是新一筆記錄的開始。in->->abigeato前一筆(空)記錄和新的「abigeato」記錄之間的分隔符號)
  • 使用“->”和換行符列印修改後的記錄。

總而言之,這些將改變最後的一句台詞:

$ perl -0 -p -e 's/[\N{U+002D}\N{U+00AD}\N{U+2010}\N{U+2011}]\h*\n//g;
                 s/\n+(?!->)//g' input2.txt

對此:

perl -n -e 'BEGIN { $/="->" };
            chomp;
            next if m/^\s*$/;
            s/[\N{U+002D}\N{U+00AD}\N{U+2010}\N{U+2011}]\h*\n//g;
            s/\n+//g;
            print "->$_\n"' input2.txt

此版本的輸出與原始版本相同,只是最終輸出行保證以換行符 ( \n) 結尾。原始版本並沒有保證這一點,事實上,它通過刪除所有後面沒有跟隨的換行符來阻止它->\n這是一個免費的獎勵,因為從技術上講,如果每行都以 ... 結尾,則文件只是 unix 中的文本文件。版本來說不是) ,但是如果“文字檔案”的最後一行不以\n.結尾,某些程式將無法正確處理它。

(順便說一句,原來的問題可以透過添加 END 區塊來修復,將換行符添加回輸出的末尾END { print "\n" }:)

$/是一個 perl 變量,它定義輸入記錄分隔符(man perlvar有關 perl 預定義/特殊/控制變量的詳細信息,請參閱 ),類似於RS中的變量awk。以前,我使用 perl 的-0選項將其設定為 NUL 字元(man perlrun有關 perl 命令行選項的詳細信息,請參閱 )。

BEGIN語句在腳本的開頭發生一次,在while(<>) { ..... }使用 perl-p-n選項引起的隱式循環之前和之外(這使得 perl 的行為有點像超級sedsed -n分別)。類似地,END在讀取和處理所有輸入之後,語句在腳本末尾發生一次。

答案2

我建議使用以下模式在單一腳本中執行此操作N;P;D

sed -e ':loop' -e '$!N;/\n->/!s/-*\n/ /;tloop' -e 'P;D'

您循環新增 'N'ext 行並使用可選的破折號 ( ) 刪除換行符s/-*\n/ /,直到新行以 開頭->

相關內容