您可以通過只使用那些計數,並在同一時間進行比較的命令避免中間步驟每個文件,Perl程序計算每個類型大括號的數量,並在文件名稱不匹配時打印該文件的名稱。
您必須注意/([}{]])/
部分,find
會認爲它需要做{}
的替換,如果您說/([{}]])/
。
警告:如果您試圖針對源代碼運行該代碼,則該代碼將存在誤報和否定。通過使用B::Deparse
while (1) {
print "}";
可以展開的Perl命令:考慮以下情況:
平衡,但花括號中字符串:
if ($s eq '{') {
print "I saw a {\n"
}
不平衡,但花括號中字符串
perl -MO = Deparse -nle'END {print $ ARGV if $ h {「{」}!= $ h {「}」}} $ h {$ _} ++ for /([} {])/ g '
導致:
BEGIN { $/ = "\n"; $\ = "\n"; }
LINE: while (defined($_ = <ARGV>)) {
chomp $_;
sub END {
print $ARGV if $h{'{'} != $h{'}'};
}
;
++$h{$_} foreach (/([}{])/g);
}
我們現在可以看看每一塊的程序:
BEGIN { $/ = "\n"; $\ = "\n"; }
這是由-l
選項引起的。它將輸入和輸出記錄分隔符都設置爲「\ n」。這意味着讀入的內容將被分解爲基於「\ n」的記錄,並且任何打印語句都將附加「\ n」。
LINE: while (defined($_ = <ARGV>)) {
}
這是由-n
選項創建的。它遍歷每一個通過命令行傳入的文件(或STDIN,如果沒有文件通過)讀取這些文件的每一行。這也恰好設置$ARGV
到<ARGV>
讀取的最後一個文件。
chomp $_;
這消除了無論是在從剛讀取的行($_
)的$/
變量,它在這裏沒什麼用處。這是由-l
選項造成的。
sub END {
print $ARGV if $h{'{'} != $h{'}'};
}
這是一個END塊,這段代碼將在程序結束時運行。如果存儲在與密鑰'{'
和'}'
相關聯的%h
中的值相等,則它打印$ARGV
(上次讀取的文件的名稱,參見上文)。
++$h{$_} foreach (/([}{])/g);
這需要進一步細分:
/
( #begin capture
[}{] #match any of the '}' or '{' characters
) #end capture
/gx
是返回的是字符串中被匹配的「{」和「}」字符列表中的正則表達式。由於沒有指定字符串,$_
變量(保存從文件中讀取的最後一行,參見上文)將被匹配。該列表被輸入到foreach
聲明中,該聲明然後運行它在列表中每個項目(因此名稱)前的聲明。它還設置了$_
(因爲你可以看到$_
是Perl中流行的變量)是列表中的項目。
++h{$_}
此線遞增一個與相關聯的$_
(其將是「{」或「}」,見上文)通過一個在$ h值。
謝謝你的回答! - 我接受lutz的回答,因爲他使用了我以前不知道的命令'paste'。 – 2009-08-28 15:27:37