您的位置:首页 > 其它

正则表达式需要灵活理解——Perl学习中

2007-09-03 15:17 363 查看
小骆驼书有这么一道题,看似简单,实际做起来还是要想想巧妙的办法:

写一个程序,输出有一个字母大写,而非所有字母都大写的行。它能匹配Fred,而不匹配fred 和FRED 吗。

按照上题意思,采用以下数据应该有这样的结果:

If fred ok   匹配
cute...f
Mr.fread   匹配
Fred over  匹配
FRED
Fred Fred Fred Fred
the end.
F               匹配
FFFF
fFgrd         匹配
fReD
fred

我于是编写了以下简单代码

while(<>)
{
 chomp;
 if(/[^A-Z]*[A-Z][^A-Z]*/)
 {
  print "Matched! In the line: $_ /n";
 }
}

执行结果是:

FRED,Fred Fred Fred Fred,FFFF,fReD都被匹配了。

其实是对正则表达式的应用的理解出现了偏差。

正则表达式是只要待比较对象中出现了一次便算匹配,是片断匹配,而不是整体匹配。

以FRED为例,/[^A-Z]*[A-Z][^A-Z]*/的匹配结果是:

第一个[^A-Z]*匹配0次,[A-Z]匹配到F,因为F后面是R,后面的[^A-Z]*匹配0次,所以匹配成功。

正则表达式的匹配采用以上方式并不能判断“整个对象里一定没有……”的情况,只能解决“整个对象里有……”的情况。

所以转换思路,题干是“有且仅有一次”,分解为条件一“有”,条件二“且没有多于一次”。根据正则表达式的匹配特点,大写字母出现两次或者以上都会满足大写字母两次匹配,条件二可转为“且不能两次匹配大写字母”。改写代码如下:

while(<>)
{
 chomp;
 if(/[A-Z]/) #条件一
 {
  if(! /[A-Z].*[A-Z]/) #条件二
  {
   print "Matched! In the line: $_ /n";
  }
 }
}

匹配结果完全正确!

当然 ,如果采用锚定就更简单了:

while(<>)
{
 chomp;
 if(/^[^A-Z]*[A-Z][^A-Z]*$/)
 {
  print "Matched! In line: $_/n";
 }
}

结果仍然正确:)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  正则表达式 perl