如果要讀取檔案內容,一般而言是一行一行的讀取
open(FILE, 'file.txt') or die "$!"; while( defined( $line = <FILE> )){ print $line; } close(FILE);
但是如果想要一行就讀完,perl提供一個快速的方法,也稱為貪吃模式(slurp mode):
他的原理就是把分行的符號改掉,原本是'\n' 改成未定義 undef
open(FILE, 'file.txt') or die "$!"; $/=undef; $alllines = <FILE>; print $allline; close(FILE); $/='\n';
第2行 $/ 就是分行的符號
第3行 所有的內容就會放到變數$alllines中,包括換行
第6行 把分行符號設回來
範例
這樣子可以直接進行操作,例如:
1. 加一行資料在檔案前面[2]
open(FILE, 'file.txt') or die "$!"; $/=undef; $alllines = <FILE>; # 一次讀取全部 close(FILE); $/='\n'; open(FILE, '> file.txt') or die "$!"; print FILE "這是加在最前面的一行"; print FILE $allline; close(FILE);
2.比對因為換行被切斷的文字
有些文字因為被切斷,在比對時會不成功,利用一次取回來比對,才能正確的比對,例如下面的文字
file.txt
There are several suggestions as to the origin of the phrase. The <這裡有個換行>
one most often repeated, especially within the walls of the Melton.
one most often repeated, especially within the walls of the Melton.
如果一行一行讀入,比對字串 "The one"是不會成功的,因此可用一次讀回的方法來比對,例如$alllines 是全部取回的字串。
print "The one有存在" if $alllines=~ /The one/; #比對不會成功
print "The one有存在" if $alllines=~ /The\s+one/; #比對成功
print "The one有存在" if $alllines=~ /The \none/; #比對成功
print "The one有存在" if $alllines=~ /The\s+one/; #比對成功
print "The one有存在" if $alllines=~ /The \none/; #比對成功
這裡的\s代表空白、換行、tab、\r等字元,可參考 [PERL] Regex 字元集(群組)所以比對可以成功,也可以把換行當成字元來處理,有興趣可以參考[PERL] 15-進階比對 #2--使用更多修飾子。
3. 一次讀入時要判斷到底讀入幾行
一次讀入又想知道到底總行數是多少,可以查找換行的數量。簡單的方法是把換行取代為換行再+1,因為最後一行是沒有換行符號。
$n= $alllines=~ s/\n/\n/g +1;
4. 從第n行切斷字串
一次讀入的字串如果我想保留n行,把n+1行以後的資料截掉,怎麼做?
$n=1; $kn=10; #要保留的行數 while($alllines=~ /\n/g){ $keeplines= $` if $n==$kn; $n++; } print "你要保留前$n行的內容為:".$keeplines;
使用變數 $`就能輕易的得到比對目標之前的字串,此字串不含比對成功那個換行。
結論
1. 一次讀取全部字串使用特殊變數 $/=undef
2. 一次讀取全部字串才能做跨行的比對,比傳統檔案全部讀完再相粘的方法好。
3. 注意大檔案記憶體吃得凶,例如log。
4. 特殊變數$`可以取回比對目標之前的字串。
參考資料
[1] https://perlmaven.com/slurp
[2] https://perlmaven.com/how-to-write-to-the-beginning-of-a-file