[PERL] 06-運算子 #2

URL Link //n.sfs.tw/11647

2017-08-19 11:35:51 By 張○○

續上一篇的運算子#1,另外十種運算子。

12.位元運算子 & | ^

進行位元運算會用到,結果可以參考 [PERL] 位元運算 Bitwise operation,常會被搞錯的是 '^' 不是指數,而是XOR。

13.邏輯運算子 && ||

條件判斷中常會用到的運算子,這和上面的位元運算子有一點不同。有時可以用and代替&&;or 代替 ||,兩者差別是 and/or 的優先權是運算子中最低的。

|| 在perl 的運算規則中還有另一個意義,就是傳回第一個「評估為true的結果」:

例如

$v= defined $a || defined $b || "預設字串" || die "no value";

因為 $a, $b 都沒有定義,所以 $v ="預設字串",最後一個die 是根本不會執行到,多此一舉。但可以用這種方法決定預設值。

另一個常見的用法,在開啟檔案時常會這樣寫:

open("inFILE", './somefile.txt') || die "Can't open file: $!\n";

意思會先去開檔案,開不成功第1個項目會是FALSE,再處理第二個項目 die~~~

&& 在perl 的運算規則中也有另一個意義,就是傳回第一個「評估為false的結果」, 不過我不知道要用在哪!

14.範圍運算子 .. ...

範圍運算子又稱flip-flop operator,有兩種表示法:兩個點 '..' 或是三個點 '...',其組成是:

左運算元 .. 右運算元
左運算元 ... 右運算元

範圍運算子很難理解清楚,官網上是這樣寫:

左運算元、右運算元就像是一個開關,只要左運算元成立,就打開開關( 為 true);到右運算元成立,則關閉開關 (false)。而兩個點 .. 左邊使開關打開後,"同時"會再比對右運算元,看是否成立,若右運算元成立,就會把開關關閉;使用三個點,則會在左邊開關打開後,同字串就不再驗證右邊運算元。也就是關閉的開關要交給後面的變數來決定。

說真的我看不太懂 > <,但我知道可以怎麼用:

指定陣列

陣列是以 '@'符號作開頭,在後面的單元會再介紹。

@array = (1..10); # 產生一個 1,2,3...10的數字陣列
@array = ('01'..'10'); # 產生一個 01,02,03...10的字串陣列
@array = ("A".."J");  # 產生一個 'A','B' .. 'J''的字元陣列
@array = ("AX".."BJ"); # 產生一個 'AX','AY','AZ','BA' .. 'BJ''的字串陣列

列表

代表一個範圍,可以做出神奇的功能

for (101 .. 200) { print; } # 101102103...200

放在for裡面的範圍運算子就相當於這樣:

  for($i=101;$i<=200;$i++){ print $i; }

陣列的切片

這個運算子可以輕易的做出切片(array_slice)的功能

@array = ('01'..'20'); # 產生一個 01,02,03...20的數字陣列
@slice= @array[4..12];  #切出第4到第12
print @slice; # 050607080910111213
@slice= @array[-5..-1];  #切出倒數第5到尾端
print @slice; #1617181920

15. (三元)狀態運算子 ?:

三元運算子很容易,常用的寫法:

$comment = $score>=60 ? '及格' : '不及格';

意思是先判斷變數$ok的真假,如果真的話 $a=$b,如果$ok為假,則$a=$c。

三元運算子有時可以取代if..else的使用,同時它也有逆向的寫法:

($ok ? $a : $b) = $c; 

意思是先判斷變數$ok的真假,如果真的話 $a=$c,如果$ok為假,則$b=$c,反向來決定$a或b何者為$c。

16. 指派運算子,有 = += -= *= 等

有這些可以用 = **= += *= &= <<= &&= -= /= |= >>= ||= .= %= ^= x=

舉個例,原本的式子是讓$a *5。

  $a = $a*5;

簡化為指派運算子寫成

  $a *= 5;

這樣看起來簡單也易讀。有些指派運算子是PERL專有的,例如:

$a=12; $a **= 2; # 144,$a的2次方
$a=12; $a %= 10; # 2,餘數除法餘10餘2
$a=12; $a &&= 3; # 3
$a=12; $a &= 2; # 0
$a=12; $a |= 2; # 14
$a=12; $a ||= 3; # 12
$a = 12; $a x= 5; # 1212121212 12印5次

第3行和第7行在前面的第13項「邏輯運算子」中有提過,具有評估的功用,||是會回傳第一個為真的結果,&&是第一個為真的話回傳第2個結果,所以

  $a &&= 2; 等同於 $a = $a && 3; 因為$a=12必為真,所以傳回第2個結果3
  $a ||= 3; 等同於 $a = $a || 3; 因為$a=12必為真,所以傳回第1個結果12

第4行和第6行是位元運算
  $a &= 2; 等同於 $a = 12 & 2; 以二進位表示 $a= 1100 & 0010,等於0000=>0
  $a |= 2; 等同於 $a = 12 | 2; 以二進位表示 $a= 1100 | 0010,等於1110=>14

17. 指定運算 =>

前面提過的,常數在指定值時有用到 '=>' ,這是一個指定運算,使用的時機不多

  use constant FOO => "something";

另外在PERL hash (中文叫「雜湊」,後面的章節會介紹) 中會用到:

  %h = ( 'John' => 23, 'Tom'=>30, 'Mary' => 25 );

要注意的是指定運算符號'=>'和第1項「物件指標」符號'->'不一樣,不要寫錯了。

18.清單運算子

清單運算子(list operator)在PERL是一種怪異的存在,而且還有分方向向左方向向右兩種。無論哪種方向都是以逗號','作為分隔。

方向向左
基本上只要是逗號分隔的清單在PERL裡會視為向左的清單運算子。但向左的清單運算子優先權是最高的,放在這只是為了比較。

print "this","is",1, "book"; # thisis1book
@ary = (1, 3, sort 4, 2);
print @ary;             # prints 1324

方向向右

方向向右的清單運算子有時不好理解,其實這是PERL本身沒有所謂的函式,有副程式要傳參數進去時的一種替代方式。例如開檔案時會這樣寫:

open HANDLE, "filename" or die "Can't open file\n";

這裡的HANDLE, "filename" 就是要傳給open這副程式的參數,由於他的優先權還高於or,因此可以省略小括號。如果要用||代替or,小括號就不能省:

open (HANDLE, "filename") || die "Can't open file\n";

的確不好理解吧。

19.符號運算子 not

這個和邏輯算子 ! 同義,只是優先權非常低。

20 邏輯運算子 and

這個和邏輯算子 && 同義,只是優先權非常低。

21.邏輯運算子 or xor

and 和 or的運算子優先權最低,寫的時候一定要特別小心,否則除錯會除死人:

$a = $b && $c;     # 等於 $a = ($b && $c); 正確
$a = $b and $c;   # 等於 ($a = $b) and $c; 這不是你要的
$a = $b || $c;        # 等於 $a = ($b || $c); 正確
$a = $b or $c;       # 等於 ($a = $b) or $c; 這更不是你要的

所以使用上除非有把握,不然not and or xor這些運算子少用點。

運算子這兩篇花了我非常多的時間,希望初學者能很快的了解,雖然範圍運算子我還不是很清楚啦!

的確,PERL的運算子有些真的很難理解,也不是這麼好用,像是有名稱的一元運算子、推位運算子、範圍運算子等。如果用法不清楚或是沒把握它的優先權的話,建議是先加個小括號來確保。

上一篇 05-運算子 #1
下一篇 07-陣列 #1

 

延伸閱讀

[PERL] 位元運算 Bitwise operation