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

5. 使用环视功能为数值添加逗号

    四种类型的环视:
    · 肯定逆序环视    (?<= ......)      子表达式能够匹配左侧的文本
    · 否定逆序环视    (?<!  ......)      子表达式不能匹配左侧的文本
    · 肯定顺序环视    (?= ......)        子表达式能够匹配右侧的文本
    · 否定顺序环视    (?!  ......)        子表达式不能匹配右侧的文本
     对于肯定顺序环视,从左至右查看文本,尝试匹配子表达式,如果能够匹配,就返回匹配成功信息。例如:(?=/d)表示如果当前位置右边的字符是数字则匹配成功。对于肯定逆序环视,从右至左查看文本。
     需要注意的是,四种环视匹配的都是位置,而不是某个字符。比如:对于字符串"Jeffrey",表达式"(?=rey)"表示匹配右边是rey的位置,即Jeff与ref之间的位置。对与这个位置,如果使用字符串修改功能,就实现了对字符串的信息添加。
     $value =~ s/(?:\d)(?:\d\d\d)+$/,/g    匹配的位置为:左侧是数字,右侧到结束位置数字个数正好是3的倍数。
     以数字12345678为例:第一次匹配到2与3之间的位置,12,345678,第二次匹配到5与6之间的位置,12,345,678。
     有一种匹配$value =~ s/(\d)(\d\d\d)+$/$1,$2/g,注意这个表达式,第一次匹配到的是12345678这个整个字符串,$1=12,$2=345678,修改后为12,345678,由于第一次直接匹配到了整个字符串,所以匹配结束了,这里与环视的匹配有很大的不同,环视匹配只匹配到那个位置。

6. Text-to-HTML转换

    通过这个例子,发现原来正则表达式还可以写的错落有致。代码如下:   

undef $/;  # 进入“文件读取”模式
$text =<># 读取命令行中指定的第一个文件名
$text =~ s/&/&amp;/g;    # 把基本的HTML
$text =~ s/</&lt;/g;     # 字符&、<和>
$text =~ s/>/&gt;/g;     # 进行HTML转义

$text =~ s/^\s*$/<p>/mg  # 划分段落

# 转换为链接形式

$text =~ s{
  
\b
  
# 把地址保存到$1
  {
    
\w[-.\w]*                                 # username
    \@                   
    [-a-z0-9]+(\.[-a-z0-9]+)*\.(com|edu|info) # hostname 
  }
  
\b
}{
<a href="mailto:$1">$1</a>}gix

print $text#最后,显示HTML文本

    · $text =~ s/^\s*$/<p>/mg  # 划分段落
      /g是全局匹配符
      /m是增强行锚点,即^和$会从字符串模式切换到逻辑行模式,即对于字符串模式,一个文本只能有一个开始^和一个结束$,但是在逻辑行模式中,其中的每个行都会有各自的开始^和结束$。
    · $text =~ s{regex}{replacement}modifier
      实际上,Perl支持用户自定义分割符,默认是 s/.../.../,也可以定义为s{...}{...},或者S|...|...|
      对于s{...}{...}由于分割符不选取了{},“/”就不再作为分割符了,因此</a>中的“/”就可以直接使用了,不必进行转义了。
    · /x修饰符
      代码中的正则表达式如果不进行换行就会很长,读起来,注释起来都很麻烦,/x修饰符使得用户能够以“宽松排列”编排这个表达式,增强可读性。而且允许在表达式中出现,以#开头标记的注释。加上/x修饰符后,表达式中的空白字符就都变为“忽略自身”元字符。如果要用普通的空格等字符,可以对其进行转义,不转义的话,就是被忽略的元字符,此外\s总是能够匹配空白字符,这一点是没有变的。
    · 总结
    由于HTML标签中有很多</a>之类的标签,使用s{...}{...}可以省去对/的转义
    当正则表达式很长的时候,/x使得表达式可以换行且可以加入注释
    当需要匹配逻辑行的时候,/m使得^和$可以匹配逻辑行的开始和结束。

7. 处理重复单词

    要求将每句话中连续重复出现的单词进行高亮显示,并且如果某该行有重复单词出现,在该行的开始标出重复出现单词所在的文件。

$/ = ".\n"# 设定特殊的“块模式”;一块文本的终结为点号和换行号的结合体

while(<>
{
  
next unless {
      
# 匹配一个单词:
       \b              # 单词的开始位置
       ( [a-z]+ )      # 单词存储在$1
      # 匹配单词后面的任意多个空白字符和/或tag

      (               # 空白存储在$2
          (?:
              
\s          # 空白字符
              |           # |
              <[^>]+>     # <TAG>形式的tag
           )+         # 至少需要出现一次
      )
      
# 再次匹配第一个单词
       (\1\b)
  }
  
# 上面是正则表达式,下面是replacement字符串,然后是修饰符、/i、/g和/x
  {\e[7m$1\e[m$2\e[7m$3\e[m}igx
  s
/^(?:[^\e]*\n)+//mg; # 去掉所有未标记的行
  s/^/$ARGV:  /mg;      # 在每行开头加上文件名
  print;
}

    · $\ = “.\n”
      这里的$\是特殊变量,一起一行是通过换行符决定的,比如\n,这样快模式下,是通过.\n决定的。这样一句话可能跨越多个行。
    · while(<>)和print
      <>能够将字符串赋值给一个特殊的变量,并且这个变量保存了s/.../...和print作用的默认字符串 。
    · next unless代表如果当前代码块没有执行,代码块下面的代码也不必执行,类似于if() {} else continue;(C++中)
    · {\e[7m$1\e[m$2\e[7m$3\e[m}igx
      \e[7m是高亮字符的起始标记,\e[m是高亮字符的终止标记。
    · s/^(?:[^\e]*\n)+//mg;
      由于有重复单词的行中都嵌入了高亮标记代码,这里只要找到没有高亮标记的行,然会替换为空就可以实现删除没有重复单词的行乐。
    · s/^/$ARGV:  /mg;      # 在每行开头加上文件名
      ARGV提供了输入文件的名字
    · 总结
      代码直接来自书中,实际能否正常运行没有实际测试,不能保证。不过代码本身介绍了很多的知识,尤其是/m、/x修饰符,加上以前的/g、/i修饰符,对正则表达式的了解加深了。

8. 总结

    第二章通过一些例子,展示了很多正则的具体内容,对PERL也进行了一定的介绍。现在学到了很多知识:元字符含义,转义,$text =~ m/.../.../... $text =~  s/.../.../...,修饰符:/i、/g、/m、/x,环视功能等等。

posted @ 2011-07-04 18:59  xiaodongrush  阅读(448)  评论(0编辑  收藏  举报