[PERL] 05-運算子 #1

URL Link //n.sfs.tw/11644

2017-08-19 02:33:39 By 張○○

運算子(operator) 又稱算符,是不是每個語言都差不多?一般言是大同小異,perl有一些別的語言沒有的運算子,例如:

x 單一個英文字母'x',代表是「重覆」的意思
.. 兩個點,代表「範圍」
... 三個點,也代表「範圍」
=~ 比對判斷

我整理了運算子,其中:

1. 運算子的優先權由上到下
2. 同一行由左到右列
3. 性質和C-like略有不同的運算子以粉色底表示

總共有21種,介紹如下:

1. 物件指標 '->'

  物件指標有最高的優先權,例如 $obj 的 func() 副函式:
  $obj->func();

2. 自動加減運算子 ++ --

這個大家應該不陌生,++/--可置於變數前或後,例如 $ii++或 ++$ii 結果是一樣的,差別在於運算子寫在前面的會先運算完再回傳值:

$ii=1; $v= ++$ii; #$v=2
$ii=1; $v= $ii++; #$v=1

但Perl 還可以對 ++ 做更奇怪的計算(-- 不適用),如果目標是1字串,且2符合這個規則/^[a-zA-Z]*[0-9]*$/,好像是EXCEL的欄位編號:

print ++($foo = '99'); # prints '100'
print ++($foo = 'a0'); # prints 'a1'
print ++($foo = 'Az'); # prints 'Ba'
print ++($foo = 'zz'); # prints 'aaa'

3. 指數運算子 **

指數運算子由兩個星星符號'**'來代表,不是一般會用的'^',例如 $ii 的四次方寫作 $ii**4。指數運算子的優先權很高,所以:

print -2**4;  #-16
print 2**2*3;  #12

4. 符號運算子 ! ~ \ 正負號 + -

! 和 NOT 同義,差別只是優先權 !高,是邏輯上的相反,比較要注意的是他們的相反值可不是你想的0或1

$a=undef;
print "Y\n" if defined( $a);  # print nothing
print !$a;   # !$a =1
$a=1;
print !$a;  # !$a = "" 空值,但是不為 undef
print "Y\n" if defined( !$a); # print Y
$a="";
print !$a;  # !$a =1 空值的 ! 反而變成 1

~ 是補數運算,可參考 [PERL] 位元運算 Bitwise operation 最下面

   print ~1;  # 18446744073709551614

\  是指標運算,可以讓變數變成位址參照,類似C的位址位址符號 '&',例如:

   $scref = \$foo;
   $arrref= \@ARGV;

5. 比對運算子 =~ !~

PERL最厲害的比對用運算子,在 [PERL] 04-基本比對 有提到。

6. 乘除運算子 * / % x

% 是餘數除法,很多語言都有,正數沒問題 10%8=2;但負數就要注意了, -10 %8=6
  PERL定義 $a % $b 為 $a 減去$b 的倍數中最小於$a且最接近 $a 的值,所以 -10 % 8=6;

x 是字串重覆乘法

print '-' x 40; # 印40個'-'
$a = 1 x 10; # 1111111111
PERL沒有整數除法的運算子,所以自己寫:

解法一 先減掉餘數再除 ($a - ($a % $b)) / $b 這種作法遇到負數會有問題,例如 -10整除8 =-2
解法二 使用 int 函數,int 是取浮點數的整數部分,例 int (-10/8) =-1 ,看來沒問題,但是看看下面這個範例:
    print -6.725/0.025;   # -269
    print int -6.725/0.025;   #-268 ,原來用int 系統算出來的值會是 -268.99999999999994315658 所以這個函數也不能用
解法三  使用 sprintf 函數 $result = sprintf("%.0f",  -6.725/0.025);  # -269 是正解,還真不容易。

7. 加減運算子 + - .

. 是字串相黏運算子

8. 推移運算子 << >>

聽說常會用這個的都是高手

$a=9; $a>>1; #4
$a=9; $a<<1; #18

9. 有名稱的一元運算子 (named unary operators)

這是 perl 裡很有特色的運算子,也可以當他是只有一個參數的函數,其實我沒完全搞懂,但倒是常常在用,例如 localtime, sleep, scalar, int...

有名稱的一元運算子優先權很高,但注意print 不是有名稱的一元運算子,他是一個串列運算子,看吧!不是這麼容易分清楚的。

看人家的範例,rand是一個產生亂數的函數,如果要寫出正確的結果,就要看懂下面的差異,如果真的搞不清楚,就用第二式的寫法,把rand 當函數來用就好了。

rand 10 * 20; # rand (10 * 20)
rand(10) * 20; # (rand 10) * 20
rand (10) * 20; # (rand 10) * 20
rand +(10) * 20; # rand (10 * 20)

PERL裡面還有一種很特別的叫作檔案測試運算子,是由一個減號和英文字母組成,和你在SHELL常會看到的差不多:

-w | 檔案或目錄, 對目前 (有效的) 使用者或群組來說, 是可寫的.
-e | 檔案或目錄是存在的
-f | 檔案代號是文字檔
-d | 檔案代號是目錄

這些運算子可以參考[1],例如判斷檔案是否為文字檔:

  if( -f '/path/to/your_file.txt'){ ... }

判斷該名稱是否為目錄:

  print "是一個目錄" if -d '/home/axer';

10.比較運算子 < > <= >= lt gt le ge

[PERL] 03-條件式判斷中已有提過這個運算子,相信大家已經不陌生了。

11.比較運算子 == != <=> eq ne cmp

同上,數值的比較用 == != ,字串的比較用 eq ne;

<=> 是數值的比較。如果左邊大傳回1;相等傳回0;左邊較小傳回-1

cmp 字串的比較。如果左邊大傳回1;相等傳回0;左邊較小傳回-1

$left=9;
$right=12;
print $left <=> $right; # -1
print $left cmp $right; # 1

先介紹11組的運算子,接下來介紹另外10組

上一篇 04-基本比對
下一篇 06-運算子 #2

參考資料

[1] https://puremonkey2010.blogspot.tw/2010/09/perl-ch12.html