正则表达式实用技巧

所在路径和文件名

if ($wholePath =~ m{^(.*)/([^/]*)$}) {
# 当路径中包含文件名的时候: "/usr/bin/perl"
$path = $1 ;
$filename = $2 ;
}
else {
# 当遇到没有路径的的时候: "file.txt", 以当前路径作为文件路径
$path = "." ;
$filename = wholePath ;
}


匹配对称的括号

#!/bin/perl -w
use 5.010 ;

$_ = "foo(int var(int (*fun)[], char b))" ;

m{
'\([^()]*\)'} ; # 匹配最内层 '()'

$depth = 3 ; # 匹配指定层数的 '()', 其缺陷就是不能匹配如 'int foo(int (*a)())' 的情况
$regex = '\([^(]*' x ($depth-1) .'\([^()]*\)' . '[^)]*\)' x ($depth-1) ;
m
/$regex/ ;

say $
& ;

  
匹配任意数字

#!/bin/perl -w
use 5.010 ;

my @nums = qw/0 1 14.23 0.12 .234 1. -0 -1 -2.4 -0.2 -.23 -4. 1.1.1/ ;

foreach (@nums) {
if (m/^-?[0-9]+(\.[0-9]+)?$/) {
printf "%8s", $_ ;
printf "%18s", ' is number.'."\n" ;
}
else {
printf "%8s", $_ ;
printf "%18s", ' is not number.'."\n" ;
}
}


判断非素数 (引自: 酷壳 coolshell.cn)

m/^1$|^(11+?)\1+$/ ;            # 前提是把数字换成等量个数的 1, 如 3 => 111, 9 => 111111111.

  首先,我们看到这个表达式中有“|”,也就是说这个表达式可以分成两个部分:/^1?$/ 和 /^(11+?)\1+$/

  • 第一部分:/^1?$/, 这个部分相信不用我多说了,其表示匹配“空串”以及字串中只有一个“1”的字符串。
  • 第二部分:/^(11+?)\1+$/,这个部分是整个表达式的关键部分。其可以分成两个部分,(11+?)\1+$,前半部很简单了,匹配以“11”开头的并重复0或n个1的字符串,后面的部分意思是把前半部分作为一个字串去匹配还剩下的字符串1次或多次(这句话的意思是——剩余的字串的1的个数要是前面字串1个数的整数倍)。

   可见这个正规则表达式是取非素数,要得到素数还得要对整个表达式求反。通过上面的分析,我们知道,第二部分是最重要的,对于第二部分,举几个例子,

示例一:判断自然数8。我们可以知道,8转成我们的格式就是“11111111”,对于(11+?),其匹配了“11”,于是还剩下“111111”,而\1+$正好匹配了剩下的“111111”,因为,“11”这个模式在“111111”出现了三次,符合模式匹配,返回true。所以,匹配成功,于是这个数不是质数。

示例二:判断自然数11。转成我们需要的格式是“11111111111”(十一个1),对于(11+?),其匹配了“11”(前两个1),还剩下“111111111”(九个1),而\1+$无法为“11”匹配那“九个1”,因为“11”这个模式并没有在“九个1”这个串中正好出现N次。于是,我们的正则表达式引擎会尝试下一种方法,先匹配“111”(前三个1),然后把“111”作为模式去匹配剩下的“11111111”(八个1),很明显,那“八个1”并没有匹配“三个1”多次。所以,引擎会继续向下尝试……直至尝试所有可能都无法匹配成功。所以11是素数。

通过示例二,我们可以得到这样的等价数算算法,正则表达式会匹配这若干个1中有没有出现“二个1”的整数倍,“三个1”的整数倍,“四个1”的整数倍……,而,这正好是我们需要的算素数的算法。现在大家明白了吧。





































posted @ 2011-08-17 11:14  walfud  阅读(267)  评论(0编辑  收藏  举报