阅读笔记-精通正则表达式-第2章-入门示例及扩展-1

1. 温度转化的示例

    这一章的开始就介绍了Perl,并且使用Perl中的正则表达式,不断的加强一个温度转化的程序的功能。
    这里直接上完整的示例了:   

print "Enter a temperature (e.g., 32F, 100C):\n";
$input = <STDIN>;    # 接收用户输入的一行文本
chomp($input);       # 去掉$input尾部的换行符
if$input =~ m/^\s*([-+]?[0-9]+(\.[0-9]+)?)\s*([C,F])\s*$/i ) {
  
# $1保存了整体数值,$2保存了小数部分,S3保存了C或者F
  $inputNum = $1;
  
$type = $3;
  
if($type  =~ m/c/i) { # 如果是C或者c
    $celsius = $inputNum
    
$fahrenheit = ($celsius * 9 / 5+ 32;
  } 
else { # 如果不是C也不是c
    $fahrenheit = $inputNum;
    
$celsius = ($fahrenheit - 32* 5 / 9;
  }
  
printf "%.2f C is %.2f F\n", $celsius, $fahrenheit;
else { #匹配失败了
  print "Expecting a number followed by \"C\" or \"F\",\n";
  
print "so I don't understand \"$input\".\n";
}

    重点解释一下这行代码:$input =~ m/^\s*([-+]?[0-9]+(\.[0-9]+)?)\s*([C,F])\s*$/

    $input是一个变量

    =~ 表示匹配的意思

    m/ ... / 表示内部是一个正则表达式

    m/ ... /i表示匹配的正则表达式不区分大小写

    \s表示空白字符,包括空格,制表符,换行符,回车符。

    配的逻辑:行起始,任意多个空白字符,零个或者一个[-+],一个或者多个数字,小数部分,任意多个空白字符,一个C或者一个F,任意多个空白字符行结束。
    这个例子中,比较重要的就是,匹配一个字符串,并且能够记录其中匹配的部分,即$1,$2,$3记录正则表达式中的三个括号内容匹配到的信息。实际中,只是用了 $1,$3,$2没有用到,可是使用非捕获型括号,(?:···)。这样的话,$2就能够保存以前$3中的信息了。

2. Perl安装试用

    此前没用过PERL,虽然上面的代码是书中给出的,总有实际用Perl跑一下,因此下面简单说说我下载并且使用PERL的经历。
    首先,找到PERL的官方网站:http://www.perl.org/
    然后,下载对应操作系统的PERL二进制安装包:http://strawberryperl.com/,下载的是5.12.3.0这个版本,40MB的文件,strawberry-perl-5.12.3.0.msi。
    接着,双击strawberry-perl-5.12.3.0.msi这个文件。注意:安装的目录不能有空格,默认安装目录为"C\strawberry\"
    接着,在桌面上新建一个文件,命名为HelloWorld.pl,使用记事本方式打开这个文件,输入一下代码,并保存文件。

print "Hello,World! It's my first time to use the perl language!";
$input = <STDIN>;

    接着,双击桌面上这个文件,得到如下运行结果:

   
    最后,在窗口中,回车,该窗口就会退出了。$input = <STDIN>;就是接收一行字符,否则程序一闪就过去了,看不清输出内容。
    总体来说,如果用两个字来形容PERL,就是简单,用一个字来形容就是爽。没有IDE的启动,没有编译过程,没有各种警告与错误的提示。双击文件就运行。
    最后,将温度转化的代码使用PERL实际运行了一下,保证代码确实能够正常运行。

3. 知识总结

    ·Perl用$variable =~ m/regex/来判断一个正则表达式regex是否匹配某个字符串variable,如果匹配成功,返回true,否则返回false。
    ·相关减记法
     \t   制表符
     \n  换行符
     \r   回车符
     \s  任何空白字符(包括:空格符,制表符,回车符,换行符)
     \S  除\s之外的任何字符
     \w [a-zA-Z0-9]
     \W 除\w之外的任何字符,也就是[^a-zA-Z0-9]
     \d  [0-9],即数字
     \D  除\d外的任何字符,即[^0-9]
    ·/i 表示此次匹配不区分大小写
    ·(?:···) 这个麻烦的写法可以用来分组文本,但并不捕获
    ·匹配成功之后,Perl可以用$1,$2,$3之类的变量来保存相对应的(···)括号内的子表达式匹配的文本。使用这些变量,我们能够用正则表达式从字符串中提取信息。

4. 使用正则表达式修改文本

    匹配字符串的格式:variable =~ m/regex/
    修改字符串的格式:variable =~ s/regex/replacement/
    几个使用regex修改文本的例子:

    4.1 公函生成程序
    假设有一个公函系统,它包含很多公函模板,其中有一些标记,对每一封具体的公函来说,标记部分的值可以定制,这个定制的就是通过使用正则来修改标记部分来实现的。
    模板:
    Dear =FIRST=,
    You have been chosen to win a brand new =TRINKET=! Free!
    Could you use another =TRINKET= in the =FAMILY= household?
    Yes =SUCKER=, I bet you could! Just respond by......
    定制:
    $given = "Tom";
    $family = "Cruise";
    $wunderprize = "100% genuine faux diamond";
    填写模板
    $letter =~ s/=FIRST=/$given/g;
    $letter =~ s/=FAMILY=/$famliy/g;
    $letter =~ s/=SUCKER=/$given $family/g;
    $letter =~ s/=TRINKET=/fabulous $wunderprize/g;
    这里的/g是“全局替换”的修饰符。它告诉s/···/···/在第一次替换完成之后继续搜索更多的匹配文本,进行更多的替换。

    4.2 修正股票价格

     对于"9.0500000037272",希望得到的形式可能是"9.05"。假设:要求是保留小数点后两位数字,如果第三位不为零,也要保留。
     $price =~ s/(小数点  小数部分的前两位   不为零的小数部分的第三位) 小数部分分的其他位/$1/
     $price =~ s/(\.\d\d[1-9]?)\d*/$1/
     注意:此处直接匹配的是小数点开始的部分,小数点起到了开始点的作用。没有直接去匹配整体的数字,如果整体匹配的话,反而会变得更加麻烦。这个例子的问题本身就是针对可能存在的小数部分进行修正,因此直接匹配小数部分更加合理。

    4.3 处理邮件的小工具

    要求编写一个名为mkreply的程序,从king.in中的邮件信息文件中,解析出邮件头部的一些字段:日期,主题等。把解析出的字段保存到king.out上面。
    输入文本,king.in:    

From elvis Thu Feb 29 11:15 2007
Received
: from elvis@localhost by tabloid.org (8.11.3) id HA8CMY
Received
: from tabloid.org by gateway.net (8.12.5/2) id N8XBK
To
: jfriedl@regex.info (Jeffrey Friedl)
From
: Elvis@tabloid.org (The King)
Date
: Thu, Feb 29 2007 11:15
Message
-Id: <2007022939939.KA8CMY@tabloid.org>
Subject
: Be seein' ya around
Reply-To: elvis@hh.tabloid.org
X-Mailer: Madam Zelda
's Psychic Orb [version 3.7 PL92]

Sorry I haven
't been around lately. A few years back I checked 
into that ole heartbreak hotel in the sky, ifyaknowwhatImean.
The Duke says "hi".
        Elvis

    输出文本,King.out:

To: elvis@hh.tabloid.org (The King)
From
: jfriedl@regex.info (Jeffrey Friedl)
Subject
: Re: Be seein' ya around

On Thu, Feb 29 2007 11:15 The King wrote:
|> Sorry I haven
't been around lately. A few years back I checked 
|> into that ole heartbreak hotel in the sky, ifyaknowwhatImean.
|> The Duke says "hi".
|>         Elvis

    perl的命令行格式:%perl  -w  mkreply  king.in  >  king.out
    其中,-w用来打开Perl的额外警告功能。
    mkreply的完整代码    

open(InFile, "$ARGV[0]") or die "open in file fail";
open(OutFile, ">$ARGV[1]") or die "open out file fail";

while($line = <InFile>) {
  
if($line =~ m/^\s*$/) { # 如果存在空行
    last# 就立即结束while循环
  }
  
if($line =~ m/^Subject: (.*)/i) { # "Subject: Be seein' ya around"
    $subject = $1;
  }
  
if($line =~ m/^Date: (.*)/i) { # "Date: Thu, Feb 29 2007 11:15"
    $date = $1;
  }
  
if($line =~ m/^Reply-To: (\S+)/i) { # "Reply-To: elvis@hh.tabloid.org"
    $reply_address = $1;
  }
  
if($line =~ m/^From: (\S+\(([^()]*)\)/i) { # "From: Elvis@tabloid.org (The King)"
    $reply_address = $1;
    
$from_name = $2;
  }
}

if( not defined($reply_address) ) {
  
die "couldn't glean the required information! reply_address.";
}

if( not defined($from_name) ) {
  
die "couldn't glean the required information! from_name."
}
if( not defined($subject) ) {
  
die "couldn't glean the required information! subject.";
}
if( not defined($date) ) {
  
die "couldn't glean the required information! date.";
}

print OutFile ("To: $reply_address ($from_name)\n");
print OutFile ("From: jfriedl\@regex.info (Jeffrey Friedl)\n");
print OutFile ("Subject: Re: $subject\n");
print OutFile ("\n");
print OutFile ("On $date $from_name wrote:\n");
while($line = <InFile>) {
  
print OutFile ("|> $line");
}

close(InFile);
close(OutFile);

    说明几点:
    ·书上的程序代码我没有调通,读文件还行,写文件好像有问题,直接修改了读写文件的方式。
      命令行格式为:%perl -w mkreply.pl king.in king.out
      Perl的命令行格式为 %perl   my.pl   $ARGV[0]   $ARGV[1]
    ·书中的程序中,有两处关于\s的使用错误了。     
      ($line =~ m/^Reply-To: (\S+)/i) 
   
   ($line =~ m/^From: (\S+\(([^()]*)\)/i)
      这两行中的(\S+)是匹配连续的非空白字符,书中误写为了(\s+)。 

posted @ 2011-07-03 16:09  xiaodongrush  阅读(484)  评论(1编辑  收藏  举报