2011-05-02 167 views
19

我試圖用perl單行來更新跨越多行的一些代碼,並且看到一些奇怪的行爲。下面是顯示問題我看到一個簡單的文本文件:perl多行匹配問題

ABCD START 
     STOP EFGH 

我希望下面的工作,但它並沒有結束更換任何東西:

perl -pi -e 's/START\s+STOP/REPLACE/s' input.txt 

後做一些嘗試,我發現原始正則表達式中的\s+將匹配換行符,但不匹配第二行中的任何空格,並且添加第二個\s+也不起作用。所以現在我做了以下解決方法,這是增加一箇中間的正則表達式,只有消除了換行:

perl -pi -e 's/START\s+/START/s' input.txt 

這將創建下列中間文件:

ABCD START   STOP EFGH 

然後我可以運行原始的正則表達式(儘管不再需要的/s):

perl -pi -e 's/START\s+STOP/REPLACE/s' input.txt 

這產生了最終所需的文件:

ABCD REPLACE EFGH 

似乎中間步驟不應該是必要的。我錯過了什麼嗎?

+0

你的常見問題的答案在第一句話:「-q的perldoc匹配」 - >「我有麻煩了一個以上的線路匹配什麼錯? 「 – tadmc 2011-05-03 00:27:32

+2

'/ s'隻影響'.'匹配的東西,所以不需要你的'/ s's – ysth 2011-05-03 01:04:56

回答

19

perl -p一次處理文件一行。你擁有的正則表達式是正確的,但它永遠不會與多行字符串匹配。

一個簡單的策略,假設該文件將裝入內存,是閱讀整個事情(做沒有-p):

$/ = undef; 
$file = <>; 
$file =~ s/START\s+STOP/REPLACE/sg; 
print $file; 

注意,我已經加入了/g修飾符來指定全局替換。

作爲所有額外樣板的快捷方式,您可以使用-0777選項perl -0777pi -e 's/START\s+STOP/REPLACE/sg'的現有腳本。如果您需要在文件中進行多次替換,則仍然需要添加/g

,你可能會遇到一個嗝,雖然沒有與此正則表達式:如果正則表達式是START.+STOP,並且文件包含多個START/STOP雙,.+貪婪匹配會吃一切從第一開始到最後一站。您可以使用非貪婪匹配(儘可能少匹配)與.+?

如果要在字符串中的任意位置使用線段邊界的^$錨點,則還需要/m正則表達式修飾符。

+0

以前我不知道關於-0pi的作品 - 作品像一個魅力 – 2012-04-18 11:50:53

+3

也找不到任何關於'-0'。那個旗子做什麼? – 2013-03-08 20:45:21

+0

這一直讓我瘋狂!非常感謝:) – PiersyP 2017-10-07 08:17:37

2
perl -MFile::Slurp -e '$content = read_file(shift); $content =~ s/START\s+STOP/REPLACE/s; print $content' input.txt 
+3

爲什麼你會讓人們使用非標準模塊來完成一個簡單的命令行將完全處理的事情? – tchrist 2011-05-03 12:53:46

3

這裏是一個一行,不將整個文件讀入內存在一次:

perl -i -ne 'if (($x = $last . $_) =~ s/START\n\s*STOP/REPLACE/) \ 
    { print $x; $last = ""; } else { print $last; $last = $_; } \ 
    print $last if eof ARGV' input.txt 
+0

不錯,雖然我不認爲ARGV正在做任何事情,可以刪除。 – 2017-10-02 05:44:35

5

一個相對簡單的一行(讀取內存中的文件):

perl -pi -e 'BEGIN{undef $/;} s/START\s+STOP/REPLACE/sg;' input.txt 

另一種選擇(不那麼簡單),不讀內存中的文件:

perl -ni -e '$a.=$_; \ 
      if ($a =~ s/START\s+STOP/REPLACE/s) { print $a; $a=""; } \ 
      END{$a && print $a}' input.txt 
18

你很近。您需要用-00-0777

perl -0777 -pi -e 's/START\s+/START/' input.txt 
+4

「-0777」和「-00」是做什麼的?我正在閱讀perl手冊頁,但除了那些數字是八進制數(顯而易見)之外,我找不到任何信息。謝謝! – 2012-07-20 16:13:31

+2

選項'-0'更改記錄分隔符。如果沒有定義記錄分隔符,則'777'激活_slurp mode_,s.t.整個文件被一次讀取。 '0'將分隔符更改爲空行。 – 2013-09-03 16:19:49