本文共 762 字,大约阅读时间需要 2 分钟。
-- Start
假设我们有这样的问题,把类似 3.690000023 的小数保留两位小数,类似 2.3563895 的小数保留三位小数,也就是说如果小数的第三位是 0, 则保留两位小数,如果是非 0, 就保留三位小数,该怎么呢? 这个问题比较简单,用下面的 Perl 代码。
$number =~ s/(\.\d\d[1-9]?)\d*/$1/;这个表达式完全可以工作,美中不足的一点是,当 $number 类似 3.695 的时候,我们把 .695 替换为了 .695,浪费了工夫。为了解决这个问题,我们把表达式稍稍修改一下。
$number =~ s/(\.\d\d[1-9]?)\d+/$1/;
仅仅把星号替换成了加号,这样表示括号外至少有一位数字的时候才进行替换。看上去很完美,但是却出现了致命的错误,.695 被替换成了 .69了。这是为什么呢?在表达式 (\.\d\d[1-9]?) 匹配了 .695 后, 后面的 \d+ 无法匹配了,为了使整个表达式匹配成功,引擎必须回溯,[1-9]?必须把匹配的数字吐出去,所以 5 被 \d+ 匹配了。这就是回溯造成的问题。事实上在这种情况下,我们不希望引擎回溯,有两种办法可以强迫引擎放弃回溯,固化分组和占有量词。
$number =~ s/(\.\d\d(?>[1-9]?))\d+/$1/; # 固化分组
$number =~ s/(\.\d\d[1-9]?+)\d+/$1/; # 占有量词引擎放弃回溯后, 上面的表达式将无法匹配 .695,这正是我们想要的。
--更多参见: -- 声 明:转载请注明出处 -- Last Updated on 2012-05-25 -- Written by ShangBo on 2012-05-25 -- End