Perl学习笔记,2----正则表达式数字匹配的一个疏忽

  《Perl语言入门》第15章习题第2题如下:

用 given-when 结构写一个程序,根据输入的数字,如果它能被3整除,就打印“Fizz”;如果它能被5整除,就打印“Bin”;如果它能被7整除,就打印“Sausage”。比如,如果输入15,程序就应该打印“Fizz”和“Bin”,因为15可以同时被3和5整除。思考一下,可以让程序输出“Fizz Bin Sausage”的最小数字该是多少?

自己写的程序如下:

 #!/usr/bin/perl
  2 use 5.010;
  3 my $num;
  4 while(chomp($num=<STDIN>)){
  5         next unless $num =~ /\A\d+\.?\d+\z/;  #防止输入的内容不是数字
  6         given($num){
  7                 when( not $_%3 ){
  8                         print "Fizz ";
  9                         continue;
 10                 }
 11                 when( not $_%5 ){
 12                         print "Bin ";
 13                         continue;
 14                 }
 15                 when( not $_%7 ){
 16                         print "Sausage ";
 17                         continue;
 18                 }
 19                 default { print "\n";}
 20         }
 21 }

结果运行的时候,发现输入 3 、5 、7 ,没有任何输出,而输入 15、 35 、21 之类的数字,却可以有 “Fizz Bin”、 “Bin Sausage” 之类的输出,怎么回事呢?

仔细推敲,原来问题出在第5行的正则表达式的代码上:

该行代码的本意是测试输入的内容是否为数字,如果不是数字,则进入下一次循环,读取下一次的输入;但匹配的模式中,'\d+' 要求至少匹配一个数字字符,则两个'\d+'则要求至少匹配两个数字字符。于是,当输入为 3 、 5、 7 的时候,因为是单个数字字符,因而无法正常匹配,就进入了下一次的循环。解决方案是使用 '/\A\d+\.?\d?/' 这个模式进行匹配。

 #!/usr/bin/perl
  2 use 5.010;
  3 my $num;
  4 while(chomp($num=<STDIN>)){
  5         next unless $num =~ /\A\d+\.?\d?\z/;  #防止输入的内容不是数字
  6         given($num){
  7                 when( not $_%3 ){
  8                         print "Fizz ";
  9                         continue;
 10                 }
 11                 when( not $_%5 ){
 12                         print "Bin ";
 13                         continue;
 14                 }
 15                 when( not $_%7 ){
 16                         print "Sausage ";
 17                         continue;
 18                 }
 19                 default { print "\n";}
 20         }
 21 }

问题解决!