Chinaunix首页 | 论坛 | 博客
  • 博客访问: 531797
  • 博文数量: 126
  • 博客积分: 851
  • 博客等级: 准尉
  • 技术积分: 1287
  • 用 户 组: 普通用户
  • 注册时间: 2012-10-06 11:21
个人简介

个人最新博客地址http://www.skylway.com/

文章分类

全部博文(126)

文章存档

2016年(2)

2014年(60)

2013年(35)

2012年(29)

分类: Python/Ruby

2012-11-10 13:41:00



操作符(operator) 概述

从数学角度来看,操作符是特殊形式的普通函数;从语言学的角度来看,操作符是不规则动词,而各种数据类型则是名词。

根据带参数的多少,操作符可分为一元操作符(unary)、二元操作符(binary)、三元操作符(ternary)以及多元操作符(主要指list operators,可跟任何多参数)

操作符的性质包括元数(arity)、优先级(precedence)和附着性(associativity)。附着性包括左附、右附和不附着。

操作符一览

按照优先级从高到低,Perl的操作符列表如下:

 

Name

Associativity

Arity

Precedence Class

Terms, and

list operators(leftward)

(项与左附列表运算符)

None

0

Term指变量、引号运算符、

括号运算符(()[] {})

The Arrow Operator

(箭头操作符)

Left

2

->

Autoincrement and

Autodecrement

(自增自减)

None

1

++ --

Exponentiation

(乘方)

Right

2

**

Ideographic Unary

 Operators

(表意一元操作符)

Right

1

! ~ /  and unary + and -

Binding Operators

(捆绑操作符)

Left

2

=~  !~

Multiplicative Operators

(乘操作符)

Left

2

* / % x

Additive Operators

(加操作符)

Left

2

+ - .

Shift Operators

(移位操作符)

Left

2

<<  >>

Name Unary and File Test Operators

(有名一元和文件测试操作符)

Right

0,1

-f my do rmdir return

Relational Operators

(关系运算符)

None

2

< > <= >= lt gt le ge

Equality Operators

(等号操作符)

None

2

== != <=> eq ne cmp

Bitwise Operator

(位操作符)

Left

2

&

Bitwise Operators

(位操作符)

Left

2

| ^

Logical Operator

(逻辑操作符)

Left

2

&&

Logical Operator

(逻辑操作符)

Left

2

||

Range Operators

(范围操作符)

None

2

.. …

Conditional Operator

(条件操作符)

Right

3

?:

Assignment Operators

(赋值操作符)

Right

2

= += -= *= and so on

Comma Operators

(逗号操作符)

Left

2

, =>

List Operators(Rightward)

(右附列表操作符)

Left

0+

List operators (rightward)

Logical not

(逻辑非)

Right

1

not

Logical and

(逻辑与)

Left

2

and

Logical or xor

(逻辑或与异或)

Left

2

or  xor

各种操作符使用说明 3.3.1 项与左赋列表操作符

项在Perl的优先级最高。项包括变量、引号操作符、在各种括号内的表达式和参数用括号括起来的函数。注意chdir($foo) *20 表示 chdir $foo* 20 chdir +($foo) * 20 表示 chdir ($foo * 20)。另外要注意括号的附着性,比如print $foo, exit可能不是你所需要的,但是print($foo), exit却达到目的!另外: print ($foo*255)+1, “/n”也不能达到打印($foo*255)+1的目的!所以一定要小心!如果有疑惑,可以加括号消除歧义。

3.3.2 箭头操作符

C/C++一样,Perl的箭头操作符(->)指反引(dereference):

右边是[…]时,左边必须是数组引用;右边是{…}时,左边必须是Hash引用;左边是()时,左边必须是子程序引用或者一个对象(a bless reference)或类名(a package name)。比如,

$aref->[42]                    #an array dereference

$href->{“corned beef”}          #a hash dereferenceu

$sref->(1,2,3)                  #a subroutine dereference

$yogi = Bear->new(“Yogi”);      #a class method call

$yogi->swipe($picnic);          #an object method call

3.3.3 自增自减

Perl++--操作符与C的操作一致。但是Perl++却有一个特殊的功能:当它对/^[a-zA-Z]*[0-9]*$/形式的字符串操作时,它是带进位的字符串自增,比如:

 print ++($foo = ‘99’);     #prints ‘100’

print ++($foo = ‘a9’);     #prints ‘b0’

print ++($foo = ‘Az’);     #prints ‘Ba’

print ++($foo = ‘zz’);      #prints ‘aaa’

 3.3.4 乘方

C中没有乘方运算符,Perl的乘方运算符(**)是从FORTRAN中借鉴来的,使用Cpow(3)函数来实现。注意乘方运算符是右附的,所以-2**4是指-2**4)而不是(-2)**4

3.3.5 表意一元操作符

这些操作符基本都与求反相关:

!是逻辑求反,相当于not not的优先级更低

如果操作数是数值则是算术负。注意如果操作数是一个标识符,将返回一个负号与标识符的连接值!(如– “abc” ”-abc”, - “-abc””+abc”

位求反。注意此操作是不可移植的。 ~12332位机器与64位机器上结果是不同的!

正号无论对数值与字符串都不起作用。但是正号有特别的作用是防止括号与函数名连接。如print  +($foo*255)+1, “/n”;

对任何跟随的操作数生成一个引用

3.3.6 捆绑操作符

这些操作将一个字符表达式与模式匹配、替换或转换捆绑,否则这些操作将作用在$_变量上。

注意$_ =~ $pat等价于$_ =~ /$pat/$string !~ /pattern/等价于 not $string =~ /pattern/。如果操作作用在替换上,将返回替换的次数,一般返回是否匹配成功。

3.3.7 乘操作符

*(乘)、/()%(求模)的基本行为与C一致。关于此类操作符需说明以下几点:

l         /默认是进行浮点计算,除非use integer(这一点与C不同!)。即$i=23; print $i/2不是打印12,而是11.5

l         %将在求模前将操作数转换为整数。

l         xPerl特有的重复操作符!非常实用!如print ‘-‘ x 80;将打印一行-@ones =(5) x @one将所有@ones的元素设为5

3.3.8 加操作符

注意事项:

l         Perl+(加)-(减)操作符若作用在字符串上,会将字符串转化为数值!

l         Perl有另外的.操作符进行字符串连接。Perl不会在字符串之间加空格。如果有多个字符串需要连接,可以使用join函数。

l         Perl的字符串连接操作符类似AWK的空格。其+-将字符串转化为数值也是从AWK借鉴来的。

3.3.9 移位操作符

左移(<<)右移(>>)操作符行为与C一致,操作数必须为整数,注意结果依赖于机器表示整数的位数。

3.3.9 有名一元和文件测试操作符

Perl的有些函数实际是一元操作符,这些函数包括:

-X (file tests)

gethostbyname

localtime

return

alarm

getnetbyname

lock

rmdir

caller

getpgrp

log

scalar

chdir

getprotobyname

lstat

sin

chroot

glob

my

sleep

cos

gmtime

oct

sqrt

defined

goto

ord

srand

delete

hex

guotemeta

stat

do

int

rand

uc

eval

lc

readlink

ucfirst

exists

lcfirst

ref

umast

exit

length

require

undef

 

文件测试操作符及其意义如下

Operator

Meaning

-r

File is readable by effective UID/GID

-w

File is writable by effective UID/GID

-x

File is executable by effective UID/GID

-o

File is owned by effective UID

-R

File is readable by real UID/GID

-W

File is writable by real UID/GID

-X

File is executable by real UID/GID

-O

File is owned by real UID

-e

File exists

-z

File has zero size

-s

File has nonzero size (returns size)

-f

File is a plain file

-d

File is a directory

-l

File is a symbolic link

-p

File is a named pipe(FIFO)

-S

File is a socket

-b

File is block special file

-c

File is a character special file

-t

Filehandle is opened to a tty

-u

File has setuid bit set

-g

File has setgid bit set

-k

File has sticky bit set

-T

File is a text file

-B

File is binary file (opposite of –T)

-M

Age of file (at startup) in days since modification

-A

Age of file (at startup) in days since last access

-C

Age of file (at startup) in days since inode change

使用注意事项:

l         一元有名操作符的默认参数一般为$_next if length < 80必须用next if length() < 80

l         一元有名操作符的优先级比一些二元操作符高,所以注意sleep 4 | 3的意义;

l         文件测试时_表示延续上一测试(包括stat函数)的文件,比如print “Can do./n” if –r $a || -w _ || -x _;

3.3.10 关系操作符

应注意Perl有两套比较操作符,针对数值与针对字符串的,两者不可混用!这是Perl相对于C特别之处!Perl的关系操作符如下:

Numeric

String

Meaning

gt

Greater than

>=

ge

Greater than or equal to

lt

Less than

<=

le

Less than or equal to

==

eq

Equal to

!=

ne

Not equal to

<=>

cmp

Comparison, with signed result

另外需注意:后三套操作符的优先级比前四套低;还有<=>cmpPerl特有的关系操作符,如果左操作数比右操作数小它返回-1,如果相等返回0,如果左操作数大于右操作数返回+1<=>操作符被称为“宇宙飞船”操作符(spaceship operator)。

3.3.11 位操作符

Perl的位操作符&(AND)|OR)、^(XOR)针对数值与字符串时有不同操作:如果任一操作数是数,两个操作数都被转化为整数;如果两个操作数都是字符串,对这个字符串的每一位做位操作。如:

print “12345 & “23456”     #prints 02044

print 12345 & 23456;        #prints 4128

3.3.12 C风格逻辑操作符

Perl提供与C类似的&&logical AND)和||(logical OR)操作符。但是应注意:Perl&&||的返回值的方式与C不同:它不是返回01,而是返回最后一个计算的值!

所以可以通过如下方式赋值:

$home = $ENV{HOME} || $ENV{LOGDIR} || (getpwuid($<))[7] || die “You’are homeless!/n”;

$and = “abc” && “def”  ;     #$and值为def

$or = “abc” || “def”;           #$or 值为abc

3.3.13 范围操作符

范围操作符..实际是两个完全不同的操作符,针对不同环境意义不同

l         在标量环境中,返回一个Boolean值,它模拟sedawk的逗号操作符: if (2..10) {print;}

l         在标量环境,(3..n)返回12…n-2E0,最后一个量附加了额外的“E0”

l         ..的差别是操作符在比较左值为真后不对右值进行比较:所以if(3..3) {print:}将不打印任何行,而if(3…3){print;}将打印第3行之后的所有行。

l         在列表(List)环境中,返回从左值到右值的一个列表,注意左右值可以是数值也可以是字符串,如(‘aa’..’zz’)或(2..10)。

3.3.14 条件操作符

条件操作符的格式是:COND ? THEN : ELSE

比如,以下语句是很常见的:

printf “I have %d camel%s./n” $n, $==1 ? ”” : “s”;

另外,注意条件操作符的优先级。下面语句可以判别某一年是否闰年:

$leapyear =

$year % 4 == 0

  ? $year % 100 ==0

    ? $year % 400 == 0

         ? 1

         : 0

     :1

   :0;

$leapyear =

$year % 4 ? 0:

$year % 100 ? 1:

$year % 400? 0:1;

3.3.14 赋值操作符

Perl提供C的所有的赋值操作符,同时增加了一些自己特有的。有很多赋值操作符,如

**= x= %= &&= ||=  += -= ^=

TARGET OP= EXPR 等价于 TARGET = TARGET OP EXPR;

注意事项:

l         TARGET只求值一次,所以$var[$a++] += $value$a只增一次

l         C不同的是,Perl的赋值表达式产生一个有效的左值(lvalue)

比如: $a += 2 *= 3;等价于$a += 2; $a *= 3;

这个语句也很常见: $new = $old =~ s/foo/bar/g;

3.3.15 逗号操作符

注在标量环境中,它计算左边的所有值,扔掉,返回最右边的值。注意以下语句结果的不同:

$a = (1, 3);     #$a=3

($a) = (1,3)     #$a=1

@a=(1,3)      #@a=qw/1 3/;

=>大多数时候只是逗号操作符的同义操作符。列表操作符的优先级比逗号操作符低。

3.3.16 逻辑and, or, notxor操作符

这四个逻辑操作符比相应C操作符优先级低。所以

unlink “alpha”, “beta”, “gamma” or gripe(), next LINE; 

unlink(“alpha”, “beta”, “gamma”) || (gripe(), next LINE);等价。

但应注意or||不总能互换,比如:

$xyz = $x || $y || $z;  $xyz = $x or $y or $z;意义是不同的!

xor操作在CPerl中都没有对应因为左右两边都会计算,不会short-circuit

 

C操作符的比较 3.4.1 Perl操作符的特别之处

l         乘方(**)、比较(<=> )、模式匹配(=~ !~)、字符串连接(.)、区域操作( .. …C没有;

l         Perl对数值和字符串有两套不同的关系(比较)操作符,应注意区分。

3.4.1 CPerl没有的操作符

Perl没有C的如下操作符:取址操作符(&)、指针操作符(*,用来dereference)、类型转换操作符((TYPE))

说明:Perl没有地址,所以不需要dereference一个地址,它的确有引用,它用$@%&来反引。Perl也有*符号,也用表示一个typeglob

Perl程序由一系列声明(Declaration)与语句(Statement)构成。声明主要在编译期间起作用。Perl不要求变量显式声明,它在初次使用时自动生成,如果未被赋值,在数值环境中会被作为0,在字符串环境中会被当成””,在作为逻辑变量时将作为false。但是Perl一般使用use strict;防止使用未定义变量。

语句按复杂程度可分为简单语句、复合语句,按逻辑关系可分为条件语句、循环语句等。

简单语句

简单语句必须以分号结束,除非它是一个块的最后语句。一个简单语句可以加以下修饰符:

if EXPR

unless EXPR

while EXPR

until EXPR

foreach LIST

比如:

$trash->take(‘out’) if $you_love_me;

shutup() unless $you_want_me_to_leave;

kiss(‘me’) until $I_die;

$expression++ while –e “$file$expression”;

s/java/perl/ for @resumes;

print “field: $_/n” foreach split /:/, $dataline;

 

注意事项:

l         Perlifunless语句正常使用时后面必须是BLOCK,哪怕只有一句话,也必须加{ },这对于C程序员会觉得很别扭,但是Perl也提供了替代方案,就是将ifunless作为后修饰符。

l         Perlifunlesswhileuntil完全起相反的功能:unless EXPR等价于if ! EXPR) until EXPR等价于while (!EXPR)

l         Perluntil语句与Cdo{ }until语句的意义是不同的!Perluntil是与while相反的。until (EXPR)相当于while (! EXPR)。先测试后执行,而不是无条件执行。以后两个例子的输出是完全不同的:

$i = 0;   do{ print “abc”} until ($i == 0);           会输出abc

$i= 0;    print “abc” until($==0);                 不会输出abc

until在没有do时在最开始也会对条件进行判断,以决定是否执行前面的语句。

复合语句

在一个范围内一系列语句称为一个块(BLOCK),复合语句是由表达式与BLOCKs组成,表达式由项与操作符组成。复合语句又可以分为复合条件语句与复合循环语句。

4.2.1 条件语句(if/unless语句)

条件语句的语句如下:

if (EXPR) BLOCK

if (EXPR) BLOCK else BLOCK

if (EXPR) BLOCK elsif (EXPR) BLOCK

if (EXPR) BLOCK elsif (EXPR) BLOCK … else BLOCK

 

unless (EXPR) BLOCK

unless (EXPR) BLOCK else BLOCK

unless (EXPR) BLOCK elsif (EXPR) BLOCK

unless (EXPR) BLOCK elsif (EXPR) BLOCK … else BLOCK

 

说明

l         ifunless是互补的,unless ($x == 1) 等价于 if$x != 1)或者 if (! ($x == 1)) 

l         if/unless语句后面都是跟BLOCK,即必须有{ },哪怕只有一条语句!这是Perl很特别的地方。但是有不用括号的方法,即使用简单if/unless语句。

l         注意Perl使用elsif 试比较Celse if ,好像是缺了一个字母似地!

l         变量声明的范围从声明开始之处到所有本条件语句之内,包括elsifelse在内。如:

if ((my $color = ) =~ /red/i) {

       $value = 0xff0000;

}

elsif ($color =~ /green/i) {

     $value = 0x00ff00;

}

else{

     warn “Unknown RGB component/n”;

     $value = 0x000000;

}

语句)

循环语句的语句如下:

LABEL while (EXPR) BLOCK

LABEL while (EXPR) BLOCK continue BLOCK

 

LABEL until (EXPR) BLOCK

LABEL until (EXPR) BLOCK continue BLOCK

 

LABEL for (EXPR: EXPR: EXPR) BLOCK

 

LABEL foreach (LIST) BLOCK

LABEL foreach VAR (LIST) BLOCK

LABEL foreach VAR (LIST) BLOCK continue BLOCK

 

例如:

LINE: while () {

next LINE if /^#/;         # skip comments

next LINE if /^$/;         # skip blank lines

} continue {

$count++;

}

 

LINE: while (defined($line = )) {

chomp($line);

if ($line =~ s///$//) {

    $line .= ;

    redo LINE unless eof(ARGV);

}

# now process $line

}

 

说明:

l         while/until的进行的判断是互补的,until也是先判断再决定是否执行语句。

l         LABEL是可选的,但是在Perl实践中还是经常使用,特别是循环内有next/last/redo语句的时候。

l         注意forforeach关键字在实践上可以互换!但两者概念上是不同的。但是系统可以分别是for还是foreach操作。

l         foreach是直接对数组元素操作的,变量是真正数组元素的别名,这一点一定要清楚。比如@arr=(1,2,3,4,5); foreach $i(@arr){ $i++} @arr就变成了(23456)。

l         循环控制操作符如下:

last   LABEL  (相当于Cbreak)

next  LABEL  (相当于Ccontinue)

redo  LABEL

LABEL是可选的,如果省略,表示最内层循环。

    应明白: redo/last后不执行continue BLOCK

l         在结构化编程的最初阶段,有些人坚持循环与子程序只能有一个入口和一个出口。One-entry是一个好的思想,但是one-exit通常是不太现实的,所以Perl建议按照需要退出循环。

l         last/redo/next可以用于BLOCK,但是eval{}, sub{}, do{}却不属于循环BLOCK,同样if/unless中也不能直接使用。要使用的话,必须再加一层{}。例如:

if (/pattern/) {{

last if /alpha/;

last if /beta/;

last if /gamma/;

# do something her only if still in if()

}}

 

do {{

    next if  $x == $y;

    # do something here

}} until $x++ > $z;

 

{

    do {

        last if $x = $y ** 2;

        # do something here

    } while $x++ <= $z;

}

注意:如果仍然用 do {{ last if $x = $y ** 2 }} where $x++ <= $z; 那么last起不到作用!后面的while继续运行。                          

Perl没有正式的switchcase语句。这是因为Perl并不需要,可以用以下方式达到同样目的:

SWITCH: {

     if  (/^abc/) { $abc = 1; last SWITCH; }

     if  (/^def/) { $def = 1; last SWITCH; }

     if  (/^xyz/) { $xyz = 1; last SWITCH; }

     $nothing = 1;

}

 

SWITCH: {

     /^abc/ && do { $abc = 1; last SWITCH; }

     /^def/ && do { $def = 1; last SWITCH; }

     /^xyz/ && do { $xyz = 1; last SWITCH; }

     $nothing = 1;

}

 

子程序简介

子程序又称为函数。在Perl里子程序与函数是同一个概念。Perl允许用户自定义子程序,它们可以在主程序的任何位置,从其它文件中通过do/require/use关键字引入,或者使用eval在运行时生成,或者通过无名子程序的引用使用。

Perl的输入、输出模型非常简单:所有的输入的参数都是转化为一个标量的List,所有的函数都返回一个List列表。Perl中,数组变量@_是一个特殊的系统变量。如果函数调用时后面跟着一个用括号括起来的列表,则在函数调用期间该列表将被自动分配给一个以@_命名的特殊变量。@_是一个局部变量,它的值只在它出现的函数中有定义。return用来返回参数,如果return后面不带参数,在List环境中将返回空列表,在标量环境中将返回undef,在Boolean环境中将返回void

声明子程序:

    sub NAME;                     # A "forward" declaration.     sub NAME(PROTO);              #  ditto, but with prototypes     sub NAME : ATTRS;             #  with attributes sub NAME(PROTO) : ATTRS;      #  with attributes and prototypes 定义子程序:     sub NAME BLOCK                # A declaration and a definition.     sub NAME(PROTO) BLOCK         #  ditto, but with prototypes     sub NAME : ATTRS BLOCK        #  with attributes     sub NAME(PROTO) : ATTRS BLOCK #  with prototypes and attributes

定义无名子程序:

    $subref = sub BLOCK;                 # no proto     $subref = sub (PROTO) BLOCK;         # with proto     $subref = sub : ATTRS BLOCK;         # with attributes     $subref = sub (PROTO) : ATTRS BLOCK; # with proto and attributes

从模块中引入子程序:

    use MODULE qw(NAME1 NAME2 NAME3);

使用子程序:

    NAME(LIST);    # & is optional with parentheses.     NAME LIST;     # Parentheses optional if predeclared/imported.     &NAME(LIST);   # Circumvent prototypes. &NAME;         # Makes current @_ visible to called subroutine.   &$subref(LIST) $subref->(LIST) &$subref

注意:有带&与不带&的使用方式,Perl5后建议不用&。但是若NAME不带参数不带任何参数时,及需要将通过函数引用使用函数时( &$subref() or &{$subref}()则不可省略(但是也可以用$subref->()代替)。

例如:

sub max {         my $max = shift(@_);         foreach $foo (@_) {             $max = $foo if $max < $foo;         }         return $max;     }   $bestday = max($mon,$tue,$wed,$thu,$fri);

 

@common = inter( /%foo, /

阅读(751) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~