Perl 的特殊變數:$` $' $#陣列 $1 $2 .. $10 \1 \2 .. \10

URL Link //n.sfs.tw/12999

2019-01-04 14:06:00 By 張○○

Perl 的特殊變數 $`,  $',  $1..$9,  $#陣列名

介紹幾個PERL比對會用到的變數。

$`和 $' 

這兩個特殊變數會用在比對的時候,Perl 的特殊變數:$_ 、$+、 $&、$! 提到 $& 代表比對範圍內的全部結果,有時想要取出的並不是比對本身的字串,而是比對目標前和後的字串,這時就需要這兩個特殊變數,非常的方便:

  $` 代表比對範圍之前的字串,那個 '`'是反單引號,一般而言是數字1左邊的那個鍵。

  $' 代表比對範圍之後的字串。

來看範例:

$str="a running dog ";
if( $str =~ /ing/){
    print "\$`=$`\n";
    print "\$&=$&\n";
    print "\$'=$'\n";
}

結果
$`=a runn
$&=ing
$'= dog

第3行 $`取出ing前面的字串
第4行 $&取出ing本身比對結果的字串
第5行 $'取出ing後面的字串,注意dog前的空白也算。

這個變數在切文章時很有用,可以參考這篇PERL一次讀取檔案所有內容的方法($/)。

$#array_name

這個變數是由 "$#" 和陣列的名稱所組成,作用是取得陣列最後一個值的索引

由於陣列索引由0開始,所以陣列的項目數量就是這個特殊變數值再加上1,例如

陣列 @arr=(1,2,3); 則$#arr=2;

陣列的項目數量就是2+1=3,

因此這個變數主要的作用就是計算陣列的長度。

但是這個變數怪異的地方在於他是可以寫入值。

例如 陣列 @arr=(1,2,3); 則$#arr=2;

如果我們把 $#arr=1; 那麼就會讀不到 $arr[2]的值(不會報錯)。

相反的,如果把$#arr=3; 陣列就自動會變大,但是讀取 $arr[3] 會得到空的結果。

$1 $2 $3 $4 $5 $6 $7 $8 $9 $10 …

$1..$10  這幾個特殊變數在比對中常會用到,也就是比對的第n個結果,他的順序是由左算起來第幾個小括號來決定

我們來看一下範例,例如下面的記錄字串,我一共用了10個括號分別包起來:

$doc="<188>Nov 18 02:34:56 這是一隻豬";

if( $doc =~ /^<(\d+)>(((\w+) (\d+)) ((\d+):(\d+):(\d+))) (.+)$/){
     print "\$0=$0\n";
     print "\$1=$1\n";
     print "\$2=$2\n";
     print "\$3=$3\n";
     print "\$4=$4\n";
     print "\$5=$5\n";
     print "\$6=$6\n";
     print "\$7=$7\n";
     print "\$8=$8\n";
     print "\$9=$9\n";
     print "\$10=$10\n";
}

執行結果

$0=01.pl  <== $0也是特殊變數,代表目前的檔案名稱
$1=188
$2=Nov 18 02:34:56 <==左邊算來第2個左刮號,以此類推
$3=Nov 18
$4=Nov
$5=18
$6=02:34:56
$7=02
$8=34
$9=56
$10=這是一隻豬

如果刮號超過10個就繼續寫 $11 $12 .... 但我不知道可以寫到多少?

上例中只有10個刮號,如果印 $11 會出現什麼?讓你失望了,只是一個空值而已。

\1 \2 \3 .. \9 \10 ...

上面錢號帶著數字的特殊變數如果把 '$' 換成反斜線 '\' 的話,就是$1 $2 $3 ..$9 $10 的替代型。

使用時機就是把比對的結果再拿進去比對的情況

換句話說,就是把符合比對的結果再丟入比對。來看以下範例,我想找出連續兩個一樣的字母,例如 good, tee, jaff , 要怎麼寫?

$str =~ /[A-Za-z]{2}/; 

上面的範例是不正確的,因為他沒把連續出現的字母表達出來,他的意思只是 A-Za-z 裡面52個字母連續出現二個的意思。

因此改寫成:

$str =~ /([A-Za-z])\1/;

那麼只要刮號中的任一個字母出現後,後面用\1代表又重覆這個字母,就能找出比對的結果。

這樣就會是正確的結果了,請自行試試看吧。

後記

這篇文章寫了三年,當初沒一口氣寫完,本來想作廢後來還是整理出來…