Learning Perl 学习笔记 Ch10 其他控制结构

  1. unlessuntil,等同于if(!)while(!),当条件判断语句的结果为false时,才会执行代码块中的内容。unless还可以带有else子句。
    demo10-1:
#!/usr/bin/perl
$_ = "apple";

print "It is $_\n";
if(/apple/){
  print "If this is an apple, then print it\n";
  $_ = "banana";
}else {
  print "If this isn't an apple, then print it\n";
  $_ = "apple";
}

print "It is $_\n";
unless(/apple/){
   print "Print it unless it is an apple\n";
   $_ = "apple";
}else {
   print "Print it unless it isn't an apple\n";
   $_ = "banana";
}

print "It is $_\n";
while(/apple/){
    print "while it is an $_, repeat\n";
    $_ = "banana";
}

print "It is $_\n";
until(/apple/){
    print "Repeat $_ until it is an apple\n";
    $_ = "apple";
}

print "It is $_\n";

结果如下:

./demo10-1
It is apple
If this is an apple, then print it
It is banana
Print it unless it is an apple
It is apple
while it is an apple, repeat
It is banana
Repeat banana until it is an apple
It is apple

  1. Perl中有一种常见的语法就是把只包含一条语句的条件代码块写成一行:前面是代码块中要执行的语句,后面跟着条件控制语句,如:
if($test < 0){
  print $test;
}

可以被改写成:
print $test if $test < 0;
所有条件控制语句都可以照此仿写,但是foreach不能自选变量,只能使用$_


  1. 裸块结构是指没有条件控制语句,只有一堆花括号括起来的代码块,作用是限定局部变量的作用范围,使用my修饰符修饰的局部变量只能在其所在的裸快内部使用
    demo10-2:
#!/usr/bin/perl
my $n = 10;
{
    print $n."\n";
    my $n += 1;
    print $n."\n";
}
print $n."\n";

调用后可以发现,裸块内第一行打印的是裸快外的变量$n,因为这时还没有声明同名的局部变量,第二行新声明了一个同名局部变量$n后(使用my关键字),这个新的变量就和原来的同名变量不同,之后在裸块内对$n的操作都是针对这个新的$n局部变量。在离开裸块后,新的$n也就消失了,又回到最初的$n

./demo10-2
10
1
10

  1. elsif而非els**e**if,是if语句的扩展,提供和其他流行语言中else if一样的功能,在多个else if子句组成的逻辑块中,Perl将先检查if中的条件表达式,如果失败,则依次检查每一个elsif中的条件表达式,直到其中有一个为真为止,如果不巧全部都为假,那就执行else子句块中的内容或什么都不做(没有else子句)
    `demo10-3:
#!/usr/bin/perl
chomp (my $input = <STDIN>);
if ($input < 0){
  print "negative\n";
} elsif ($input > 0){
  print "positive\n";
} else{
  print "zero\n";
}
./demo10-3
3
positive

  1. 自增自减操作符:++,--像大多数其他语言一样,操作符在变量之前,称为前置,对应着先对变量操作,再进行赋值;如果操作符再变量之后,称为后置,表示先用变量原先的值进行赋值,再对变量的值进行操作。
    demo10-4:
#!/usr/bin/perl
$n = 10;
print $n."\n";
print $n++."\n";
print $n."\n";
print ++$n."\n";
print $n."\n";
./demo10-4
10
10
11
12
12

  1. for结构,Perl提供和C语言一样的for循环控制结构:
    for(初始条件;判断语句;自增语句){…}
    如果是for(;;){...}那就是等同于while(1){...}的死循环
    在Perl解析器的眼中,forforeach这两个关键字是等价的,它主要是通过圆括号中的内容而非关键字来理解使用者的意图,所以我们可以任意的使用for来替换原本的foreach
    demo10-5:
#!/usr/bin/perl
for(@ARGV) {
      print $_."\n";
}
for(1 ... 10){
    print $_."\n";
}
./demo10-5 ABC DEF
ABC
DEF
1
2
3
4
5
6
7
8
9
10

  1. Perl中有五种循环块:for、foreach、while、until和裸块,通过循环控制结构可以控制循环的执行过程
    last操作符可以立刻中止循环,跳出最内层的循环块,作用等同于其他语言中的break
    demo10-6:
#!/usr/bin/perl
#打印出所有提到fred的行,直到碰到__END__记号为止
while(<STDIN>){
    if(/__END__/){
        last;
    } elsif (/fred/i){
        print;
    }
}
## last指令会跳到这里  
./demo10-6
ABC
Fred&wilma
Fred&wilma
__END__

next操作符忽略本次迭代剩余未执行的部分,跳到当前块的最后一行,然后执行下一次迭代的条件判断语句。作用等同于其他语言中的continue
demo10-7:

#!/usr/bin/perl
# 分析输入文件中的单词
while(<>){ #钻石操作符逐行读取命令行中的参数并放入$_
   foreach (split) { #使用split的默认行为将$_分成空格隔开的字符串数组,然后将每一个字符串赋值给$_,这里Perl会自动处理$_的重用
    $total++;
    next if(/\W/);  #如果碰到不是单词的字符,跳过之后的表达式
    $valid++;
    $count{$_}++;  # 用哈希统计每个单词出现的次数
    ## 上面的next操作符如果执行会跳到这里
    }
}

print "total things = $total, valid things = $valid.\n";
foreach $word (sort keys %count) {
    print "$word was seen $count{$word} times.\n";
}
./demo10-7 demo10-7
total things = 42, valid things = 11.
foreach was seen 2 times.
keys was seen 1 times.
next was seen 1 times.
print was seen 2 times.
seen was seen 1 times.
things was seen 2 times.
valid was seen 1 times.
was was seen 1 times.

redo操作符返回到本次循环开始的位置,重新执行本次循环,其他语言中并没有类似的概念
demo10-8:

#!/usr/bin/perl
#打字测试
my @words = qw{ Fred barney pebbles dino wilma betty};
my $error = 0;

foreach(@words){
    ## redo指令会跳到这里
    print "Type the word `$_`: ";
    chomp (my $try = <STDIN>);
    if($try ne $_){
        print "Sorry - That's not right.\n\n";
        $error++;
        redo;  # 跳到循环开始的位置
   }
}
print "You have completed the test, with $error errors.\n";
./demo10-8
Type the word `Fred`: Fred
Type the word `barney`: bar
Sorry - That's not right.

Type the word `barney`: barney
Type the word `pebbles`: pell
Sorry - That's not right.

Type the word `pebbles`: pebbles
Type the word `dino`: dina
Sorry - That's not right.

Type the word `dino`: dino
Type the word `wilma`: wilma
Type the word `betty`: beyty
Sorry - That's not right.

Type the word `betty`: bett
Sorry - That's not right.

Type the word `betty`: betty
You have completed the test, with 5 errors.

每次输入错误后,都会回到本次迭代的开始,重新执行。


比较last,nextredo三种操作符的差异,last跳出循环的执行,next会继续下一次迭代,而redo会重新执行这次迭代
demo10-9:

#!/usr/bin/perl
foreach(1...10) {
    print "Iteration Number $_.\n\n";
    print "Please choose: last, next, redo or none of the above? ";
    chomp($choice = <STDIN>);
    print "\n";
    last if $choice =~ /^last$/;
    next if $choice =~ /^next$/;
    redo if $choice =~ /^redo$/;
    print "That wasn't any of the choices... onward!\n\n";
}
print "That's all, folks.\n\n";
./demo10-9
Iteration Number 1.

Please choose: last, next, redo or none of the above? next #选择next

Iteration Number 2.

Please choose: last, next, redo or none of the above? #没有输入

That wasn't any of the choices... onward!

Iteration Number 3.

Please choose: last, next, redo or none of the above? redo # 选择redo

Iteration Number 3.

Please choose: last, next, redo or none of the above? last #选择 last

That's all, folks.

通过标签,可以实现从内层对外层的循环块进行控制,标签由字母数字和下划线组成,但不能由数字开头。当标签用来给代码块命名时,就可以在last,nextredo的后面加上标签的名字,实现对循环的精确控制
demo10-10:

#!/usr/bin/perl
LINE: while(<>){
    print "[LINE]$_";
WORD:  foreach(split){
                  last LINE if /end/i;
                  next WORD if /\W+/;
                  print "[WORD]$_\n";
              }
}
 ./demo10-10
hello world
[LINE]hello world
[WORD]hello
[WORD]world
I have a dream!
[LINE]I have a dream!
[WORD]I
[WORD]have
[WORD]a
end test
[LINE]end test

  1. 三目操作符?:是经典的if-then-else控制结构的简化表达形式,在C和Java中都有使用。他看起来像这样:
    条件表达式 ? 真表达式 : 假表达式
    三目表达式和if-else结构等价,但更简洁,多层if-elsif-else结构可以用三目表达式的嵌套来实现
    demo10-11:
#!/usr/bin/perl
print "Please type in the width:";
chomp($width = <STDIN>);
print "\n";

my $size = 
    ($width < 10) ? "small" :
    ($width < 20) ? "medium" :
    ($width < 50) ? "large":
            "extra-large"; # default
print "The size is $size\n";

  1. Perl提供C语言的全部逻辑操作符,包括&&,||, !异或^,而且可以使用单词代替逻辑符号(但是单词的优先级很低),如and = &&, or = ||,no = !,xor=^
    Perl的逻辑运算也会遵循短路原则,即如果逻辑运算符的左式在逻辑上已经可以计算出最终的结果,则不会执行右式。如:
    ($a < $b) || ($c>$d)如果$a确实小于$b,则不需要再判断$c$d的大小。
    demo10-12:
#!/usr/bin/perl
print "Please type in \$a:";
chomp($a = <STDIN>);
print "\nPlease type in \$b:";
chomp($b = <STDIN>);
print "\n";
($a == $b)||(print "\$a:$a != \$b:$b\n");
 ./demo10-12
Please type in $a:1
Please type in $b:1

 ./demo10-12
Please type in $a:2
Please type in $b:3
$a:2 != $b:3

和C语言不同,Perl中逻辑操作符返回的并不是布尔值,而是逻辑表达式执行的结果,考虑到短路行为,逻辑操作符返回的就是最后执行的表达式的结果。在Perl中,这种结果恰和布尔值兼容。
利用短路操作符可以实现初始化赋默认值的功能
demo10-13:

#!/usr/bin/perl
my $last_name = $last_name{$someone} || 'no last name';
print "$last_name\n";
./demo10-13
no last name

因为哈希中不存在键$someone,所以左边的结果是undef,也就是“假”,则对操作符右边的表达式求值,并使其成为逻辑“或”操作符的结果,存入变量$last_name
但是,如果哈希中存在一个键的内容是数字0或者字符串空,这些在Perl中被视作布尔值false的等价物
demo10-13-1:

#!/usr/bin/perl
$someone = "Fred";
$last_name{$someone} = 0;
my $last_name = $last_name{$someone} || 'no last name';
print "$last_name\n";

这时逻辑“或”操作符的左式执行结果也是false

./demo10-13-1
no last name

如何在这种情况下区分出左式为“假”是因为变量的内容是undef还是由于变量被用户不小小心定义成了“false”的等价物?Perl在5.10中引入了“定义否”操作符//,只有在操作符左式内的变量确实是undef时,左式才为假,其他情况下左式都为“真”
demo10-13-2:

#!/usr/bin/perl
$someone = "Fred";
$last_name{$someone} = 0;
my $last_name = $last_name{$someone} // 'no last name';
print "$last_name\n";
./demo10-13-2
0
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,657评论 6 505
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,889评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,057评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,509评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,562评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,443评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,251评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,129评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,561评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,779评论 3 335
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,902评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,621评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,220评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,838评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,971评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,025评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,843评论 2 354

推荐阅读更多精彩内容