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

小骆驼书有这么一道题,看似简单,实际做起来还是要想想巧妙的办法:

写一个程序,输出有一个字母大写,而非所有字母都大写的行。它能匹配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";
 }
}

结果仍然正确:)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值