Perl笔记:13、智能匹配与given-whe…
2013-10-14 12:54
323 查看
智能匹配操作符
Perl 5.10版本中的智能匹配操作符(~~)会根据需要选择恰当的方式比较两端的操作数。它只用于判断操作数是否相同,在比较大小时就不能用了,老老实实的用传统的比较操作符吧。智能匹配操作符~~和前面讲的绑定操作符=~很像,不过相对来说~~操作符更强悍一些。他甚至可以代替绑定操作符。如下:
先前用绑定操作符
print "I found Fred in the name!\n" if $name =~ /Fred/;
现在可以使用智能匹配操作符代替,可以完成同样的任务:
use 5.010; print "I found Fred in the name!\n" if $name ~~ /Fred/;
只能匹配操作符看到左侧是个标量,右侧是个正则表达式,于是它自己推断出应该执行模式匹配操作。这只是一个简单的例子,在处理更复杂的情况时,它就该大显身手了,如,你想在哈希%names中查找任何匹配Fred的键,如果找到就打印输出一条信息。这时你无法使用exists判断,因为它需要给定确切的键,当然你可以用foreach来遍历每个键,尝试用正则表达式匹配,跳过不匹配的,直到发现要找的键,最后用last退出:
1 2 3 4 5 6 7 | my $flag = 0; foreach my $key (keys %names){ next unless $key =~ /Fred/; $flag = $key; last; } print "I found a key matching 'Fred'. It was %flag\n" if $flag; |
版本都支持,但相对于智能匹配操作符来说就显得很麻烦了,下面使用智能匹配操作符来搞定它:
use
5.010;
say "I found a key matching
'Fred'" if %names ~~ /Fred/;
--这里智能匹配操作符发现了左侧是一个哈希,右侧是一个正则表达式,因此它聪明的遍历%names的所有键,用给定的正则表达式逐个测试,如果找到就立即停止,并返回真。在这里的匹配和标量的匹配不太一样,它集数种不同的操作于一身,用了一个操作符就解决了各种各样的问题。
两个数组的比较(只考虑长度相同的数组)
如果按照常规的方法可以按数组索引依次遍历,取出相同位置的两个元素比较。如果比较下来两者相抵,则令计数器$equal自增1,循环结束后如果$equal和数组@names1的长度一致则说明两个数组完全相同:
1 2 3 4 5 6 7 | my $equal = 0; foreach my $index ( 0 .. $#names1 ) { last unless $names1[$index] eq $names2[$index]; $equal++; } print "The arrays have the same elements!\n" if $equal == @names1; |
use
5.010;
say "The arrays have the same
elements!"
if @names1 ~~ @names2;
--看到了吧,仍然是这么简单,就一句话,几乎算不上是程序。
使用智能匹配是,对两边操作数的顺序没有要求,倒过来写也可以。就像代数中的“交换律”
1 2 3 | use 5.010; say "I found a name matching 'Fred'" if $name ~~ /Fred/; say "I found a name matching 'Fred'" if /Fred/ ~~ $name; |
智能匹配操作处理方式
下表是智能匹配操作符对不同操作数的处理方式例子 | 匹配方式 |
%a ~~ %b | 哈希的键是否一致 |
%a ~~ @b | 至少 %a 中的一个键在列表@b中 |
%a ~~ /Fred/ | 至少一个键匹配给定的模式 |
%a ~~ 'Fred' | 哈希中某一指定键$a{Fred}是否存在 $a{Fred} |
@a ~~ @b | 数组是否相同 |
@a ~~ /Fred/ | 有一个元素匹配给定的模式 |
@a ~~ 123 | 至少有一个元素转化为数字后是123 |
@a ~~ 'Fred' | 至少有一个元素转化为字符串后是'Fred' |
$name ~~ undef | $name确实尚未定义 |
$name ~~ /Fred/ | 模式匹配 |
123 ~~ '123.0' | 数字和字符串是否相等 |
'Fred' ~~ 'Fred' | 字符串是否相同 |
123 ~~ 456 | 数字是否相等 |
注意:当两个标量以字符串的形式存储像123,123.12这些数字的时候,使用智能匹配操作符进行比对时会默认将这些字符串转换为数字,然后在进行比对。
given语句
Perl中的given-when控制结构能够根据given的参数,执行某个条件对应的语句块,其与C语言中的switch语句类似。只不过更具有Perl的色彩。看看下面的例子,其从命令行中取出第一个参数,$ARGV[0],然后依次走一遍when条件判断,看是否找到了Fred。每个when语句对应不同的处理方式,判断的条件从最宽松的开始测试:1 2 3 4 5 6 7 | use 5.010; given( $ARGV[0] ) { when( /fred/i ) { say 'Name has fred in it' } when( /^Fred/ ) { say 'Name starts with Fred' } when( 'Fred' ) { say 'Name is Fred' } default { say "I don't see a Fred" } } |
1 2 3 4 5 6 7 | use 5.010; given( $ARGV[0] ) { when( $_ ~~ /fred/i ) { say 'Name has fred in it' } when( $_ ~~ /^Fred/ ) { say 'Name starts with Fred' } when( $_ ~~ 'Fred' ) { say 'Name is Fred' } default { say "I don't see a Fred" } } |
$ perl5.10.0 switch.pl Fred
Name has fred in it
$ perl5.10.0 switch.pl Frederick
Name has fred in it
$ perl5.10.0 switch.pl Barney
I don't see a Fred
$ perl5.10.0 switch.pl Alfred
Name has fred in it
看到这里你也许会说,Perl中的if-elsif-else语句不是一样可以完成这个例子吗,为什么还要用given-when语句呢,它还有存在的必要吗?实际上他们两个语句最大的不同在于given-when可以在满足某个条件的基础上,继续测试其他的条件,但if-elsif-else一旦满足了某个条件,就只能执行对应的那个语句块。实际上前面的例子可以写成如下的方式:
1 2 3 4 5 6 7 | use 5.010; given( $ARGV[0] ) { when( $_ ~~ /fred/i ) { say 'Name has fred in it'; break } when( $_ ~~ /^Fred/ ) { say 'Name starts with Fred'; break } when( $_ ~~ 'Fred' ) { say 'Name is Fred'; break } default { say "I don't see a Fred"; break } } |
1 2 3 4 5 6 7 | use 5.010; given( $ARGV[0] ) { when( $_ ~~ /fred/i ) { say 'Name has fred in it'; continue } when( $_ ~~ /^Fred/ ) { say 'Name starts with Fred'; continue } when( $_ ~~ 'Fred' ) { say 'Name is Fred'; continue } # 注意! default { say "I don't see a Fred" } } |
$ perl5.10.0 switch.pl Alfred
Name has fred in it
I don't see a Fred
--default块相当于一个测试条件永远为真的when语句。如果在default之前的when语句使用了continue,Per就会继续执行default语句。因此可以说default就是一个特殊的when:
1 2 3 4 5 6 7 | use 5.010; given( $ARGV[0] ) { when( $_ ~~ /fred/i ) { say 'Name has fred in it'; continue } when( $_ ~~ /^Fred/ ) { say 'Name starts with Fred'; continue } when( $_ ~~ 'Fred' ) { say 'Name is Fred'; continue } # 注意! when( 1 == 1 ) { say "I don't see a Fred" } # 相当于default语句块 } |
1 2 3 4 5 6 7 | use 5.010; given( $ARGV[0] ) { when( $_ ~~ /fred/i ) { say 'Name has fred in it'; continue } when( $_ ~~ /^Fred/ ) { say 'Name starts with Fred'; continue } when( $_ ~~ 'Fred' ) { say 'Name is Fred'; break } # 现在就对了! when( 1 == 1 ) { say "I don't see a Fred" } # 这里的when(1==1)可改写成default } |
多个项目的when匹配
有些时候需要遍历很多元素,但given只能一次接受一个参数,当然可以将given语句放到foreach里面循环测试。比如要遍历@names,依次将各元素赋值到$name,然后再用given:1 2 3 4 5 6 | use 5.010; foreach my $name ( @names ) { given( $name ) { ... } } |
use
5.010;
foreach ( @names ) {
#
不要使用命名变量!
when( /fred/i ) { say
'Name has fred in
it'; continue }
when( /^Fred/ ) { say
'Name starts with
Fred'; continue }
when( 'Fred' ) { say
'Name is Fred'; }
default { say "I don't see a Fred" }
}
一般在遍历的时候,总希望可以看到当前的工作状态。可以在foreach语句块中写上其他的语句,比如say:
1 2 3 4 5 6 7 8 9 | use 5.010; foreach ( @names ) { # 不要使用命名变量! say "\nProcessing $_"; when( /fred/i ) { say 'Name has fred in it'; continue } when( /^Fred/ ) { say 'Name starts with Fred'; continue } when( 'Fred' ) { say 'Name is Fred'; } say "Moving on to default..."; default { say "I don't see a Fred" } } |
1、用given-when结构写一个程序,根据输入的数字,如果能被3整除,就打印“Fizz”,如果能被5整除就打印“Bin”,如果能被7整除就打印“Sausag”。比如输入数字15,程序打印“Fizz”和“Bin”
1 2 3 4 5 6 7 8 9 10 11 | #!/usr/binperl -w use strict; use 5.010; given($ARGV[0]){ when(not $_ % 3){say 'Fizz';continue} when(not $_ % 5){say 'Bin';continue} when(not $_ % 7){say 'sausage'} } |
Fizz
# perl ex_13_1.pl 15
Fizz
Bin
# perl ex_13_1.pl 105
Fizz
Bin
sausage
2、使用foreach-when写个程序,要求从命令行遍历某个目录下的文件,并报告每个文件的可读、可写和可执行属性状态。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | #!/usr/bin/perl -w use strict; use 5.010; my $SourcePath = $ARGV[0]; opendir MYDIR,$SourcePath or die "can't open $SourcePath :$!"; chdir $SourcePath; foreach (readdir MYDIR){ say "\e[32m==============================\e[0m"; when(-x $_){say "$SourcePath/$_ \e[1;32mexecutable!\e[0m";continue} when(-r $_){say "$SourcePath/$_ \e[1;35mreadable !\e[0m";continue} when(-w $_){say "$SourcePath/$_ \e[1;33mwritable !\e[0m"} } closedir MYDIR |
运行结果:
![](http://simg.sinajs.cn/blog7style/images/common/sg_trans.gif)
相关文章推荐
- Perl笔记14、进程管理
- 研究生规划
- 转:char*, char[] ,CString, stri…
- C语言 side effect 和 sequence po…
- 详解C中volatile关键字
- Python+NLTK自然语言处理学习(一…
- Python+NLTK自然语言处理学习(二…
- Python+NLTK自然语言处理学习(三…
- Flex 4 的 Spark 组件
- 判定被7整除的简易方法
- Flex keycode 对照表
- flex XML
- flex metadata tag学习【转】
- 【转】flex textArea 获…
- ActionScript 3.0著名开源库 大集…
- 转:FLEX资源
- mouseOver 和rollOver区别
- 升级Flash Builder 4.6…
- Flash Builder 4.7使用&…
- doc,view,frame互相调用