学习动态网页制作PHP技术的正则表达式
核心提示:正则表达式难于书写、难于浏览、难于保护,常常毛病匹配意料不到的文本或错过了有效的文本,这些题目都是由正则表达式的表现和能力引发的。每个元字符(metacharacter)的能力和细微差别组合在1起,使得代码不借助于智力技能就没法解释。
正则表达式难于书写、难于浏览、难于保护,常常毛病匹配意料不到的文本或错过了有效的文本,这些题目都是由正则表达式的表现和能力引发的。每个元字符(metacharacter)的能力和细微差别组合在1起,使得代码不借助于智力技能就没法解释。
很多包括1定特性的工具使浏览和编写正则表达式变得轻易了,但是它们又很不符合习惯。对很多程序员来讲,书写正则表达式就是1种魔法艺术。他们坚持自己所知道的特点并持有尽对乐观的态度。假设你愿意采取本文所探讨的5个习惯,你将可让你设计的正则表达式承受的住反复实验。
本文将使用Perl、PHP和Python语言作为代码示例,但是本文的建议几近适用于任何替换表达式(regex)的履行。
1、使用空格和注释
对大部份程序员来讲,在1个正则表达式环境里使用空格和缩进排列都不成题目,假设他们没有这么做1定会被同行乃至外行人士看笑话。几近每个人都知道把代码挤在1行会难于浏览、书写和保护。对正则表达式又有甚么不同呢?
大部份替换表达式工具都具有扩大的空格特性,这答应程序员把他们的正则表达式扩大为多行,并在每1行结尾加上注释。为甚么只有少部份程序员利用这个特性呢?Perl 6的正则表达式默许就是扩大空格的模式。不要再让语言替你默许扩大空格了,自己主动利用吧。
记住扩大空格的窍门之1就是让正则表达式引擎忽视扩大空格。这样假设你需要匹配空格,你就不能不明确说明。
在Perl语言里面,在正则表达式的结尾加上x,这样“m/foo|bar/”变成以下情势:
m/
foo
|
bar
/x
在PHP语言里面,在正则表达式的结尾加上x,这样“"/foo|bar/"”变成以下情势:
"/
foo
|
bar
/x"
在Python语言里面,传递模式修饰参数“re.VERBOSE”得到编译函数以下:
pattern = r'''
foo
|
bar
'''
regex = re.compile(pattern, re.VERBOSE)
处理更加复杂的正则表达式时,空格和注释就更能体现出其重要性。假定下面的正则表达式用于匹配美国的电话号码:
\(?\d{3}\)? ?\d{3}[-.]\d{4}
这个正则表达式匹配电话号码如“(314)555⑷000”的情势,你以为这个正则表达式是否是匹配“314⑸55⑷000”或“555- 4000”呢?答案是两种都不匹配。写上这么1行代码隐蔽了缺点和设计结果本身,电话区号是需要的,但是正则表达式在区号和前缀之间缺少1个分隔符号的说明。
把这1行代码分成几行并加上注释将把缺点暴露无疑,修改起来明显更轻易1些。
在Perl语言里面应当是以下情势:
/
\(? # 可选圆括号
\d{3} # 必须的电话区号
\)? # 可选圆括号
[-\s.]? # 分隔符号可以是破折号、空格或句点
\d{3} # 3位数前缀
[-.] # 另1个分隔符号
\d{4} # 4位数电话号码
/x
改写过的正则表达式现在在电话区号后有1个可选择的分隔符号,这样它应当是匹配“314⑸55⑷000”的,但是电话区号还是必须的。另1个程序员假设需要把电话区号变成可选项则可以迅速看出它现在不是可选的,1个小小的改动便可以够解决这个题目。
2、书写测试
1共有3个层次的测试,每1层为你的代码加上1层可靠性。首先,你需要认真想想你需要匹配甚么代码和你是否是能够处理毛病匹配。其次,你需要利用数据实例来测试正则表达式。最后,你需要正式通过1个测试小组的测试。
决定匹配甚么实在就是在匹配毛病结果和错过正确结果之间寻求1个平衡点。假设你的正则表达式过于严格,它将会错过1些正确匹配;假设它过于宽松,它将会产生1个毛病匹配。1旦某个正则表达式发放到实际代码当中,你可能不会二者都留意到。考虑1下上面电话号码的例子,它将会匹配“800⑸55⑷000 = ⑸355”。毛病的匹配实在很难发现,所以提早计划做好测试是很重要的。
还是使用电话号码的例子,假设你在Web表单里面确认1个电话号码,你可能只要满足于任何格式的10位数字。但是,假设你想从大量文本里面分离电话号码,你可能需要很认证的排除不符合要求的毛病匹配。
在考虑你想匹配的数据的时候,写下1些案例情况。针对案例情况写下1些代码来测试你的正则表达式。任何复杂的正则表达式都最好写个小程序测试1下,可以采取下面的具体情势。
在Perl语言里面:
#!/usr/bin/perl
my @tests = ( "314⑸55⑷000",
"800⑸55⑷400",
"(314)555⑷000",
"314.555.4000",
"555⑷000",
"aasdklfjklas",
"1234⑴23⑴2345"
);
foreach my $test (@tests) {
if ( $test =~ m/
\(? # 可选圆括号
\d{3} # 必须的电话区号
\)? # 可选圆括号
[-\s.]? # 分隔符号可以是破折号、空格或句点
\d{3} # 3位数前缀
[-\s.] # 另1个分隔符号
\d{4} # 4位数电话号码
/x ) {
print "Matched on $test\n";
}
else {
print "Failed match on $test\n";
}
}
在PHP语言里面:
$tests = array( "314⑸55⑷000",
"800⑸55⑷400",
"(314)555⑷000",
"314.555.4000",
"555⑷000",
"aasdklfjklas",
"1234⑴23⑴2345"
);
$regex = "/
\(? # 可选圆括号
\d{3} # 必须的电话区号
\)? # 可选圆括号
[-\s.]? # 分隔符号可以是破折号、空格或句点
\d{3} # 3位数前缀
[-\s.] # 另1个分隔符号
\d{4} # 4位数电话号码
/x";
foreach ($tests as $test) {
if (preg_match($regex, $test)) {
echo "Matched on $test
;";
}
else {
echo "Failed match on $test
;";
}
}
?>;
在Python语言里面:
import re
tests = ["314⑸55⑷000",
"800⑸55⑷400",
"(314)555⑷000",
"314.555.4000",
"555⑷000",
"aasdklfjklas",
"1234⑴23⑴2345"
]
pattern = r'''
\(? # 可选圆括号
\d{3} # 必须的电话区号
\)? # 可选圆括号
[-\s.]? # 分隔符号可以是破折号、空格或句点
\d{3} # 3位数前缀
[-\s.] # 另1个分隔符号
\d{4} # 4位数电话号码
'''
regex = re.compile( pattern, re.VERBOSE )
for test in tests:
if regex.match(test):
print "Matched on", test, "\n"
else:
print "Failed match on", test, "\n"
运行测试代码将会发现另1个题目:它匹配“1234⑴23⑴2345”。
理论上,你需要整合全部程序所有的测试到1个测试小组里面。即使你现在还没有测试小组,你的正则表达式测试也会是1个小组的良好基础,现在正是开始创建的好机会。即使现在还不是创建的合适时间,你也应当在每次修改以后运行测试1下正则表达式。这里花费1小段时间将会减少你很多麻烦事。
1 2 下1页
核心提示:正则表达式难于书写、难于浏览、难于保护,常常毛病匹配意料不到的文本或错过了有效的文本,这些题目都是由正则表达式的表现和能力引发的。每个元字符(metacharacter)的能力和细微差别组合在1起,使得代码不借助于智力技能就没法解释。
3、为交替操纵分组
交替操纵符号(|)的优先级很低,这意味着它常常交替超进程序员所设计的那样。比如,从文本里面抽取Email地址的正则表达式可能以下:
^CC:|To:(.*)
上面的尝试是不正确的,但是这个bug常常不被留意。上面代码的意图是找到“CC:”或“To:”开始的文本,然后在这1行的后面部份提取Email地址。
不幸的是,假设某1行中间出现“To:”,那末这个正则表达式将捕捉不到任何以“CC:”开始的1行,而是抽取几个随机的文本。坦白的说,正则表达式匹配 “CC:”开始的1行,但是甚么都捕捉不到;或匹配任何包括“To:”的1行,但是把这行的剩余文本都捕捉了。通常情况下,这个正则表达式会捕捉大量 Email地址,所有无人会留意这个bug。
假设要符合实际意图,那末你应当加进括号说明清楚,正则表达式以下:
(^CC:)|(To:(.*))
假设真正意图是捕捉以“CC:”或“To:”开始的文本行的剩余部份,那末正确的正则表达式以下:
^(CC:|To:)(.*)
这是1个普遍的不完全匹配的bug,假设你养成为交替操纵分组的习惯,你就会避免这个毛病。
4、使用宽松数目词
很多程序员避免使用宽松数目词比如“*?”、“+?”和“??”,即使它们会使这个表达式易于书写和理解。
宽松数目词可以尽可能少的匹配文本,这样有助于完全匹配的成功。假设你写了“foo(.*?)bar”,那末数目词将在第1次碰到“bar”时就停止匹配,而不是在最后1次。假设你希看从“foo###bar+++bar”中捕捉“###”,这1点就很重要。1个严格数目词将捕捉“###bar++ +”。
假定你要从HTML文件里面捕捉所有电话号码,你可能会使用我们上文讨论过的电话号码正则表达式的例子。但是,假设你知道所有电话号码都在1个表格的第1列里面,你可使用宽松数目词写出更简单的正则表达式:
很多刚起步的程序员不使用宽松数目词来否定特定种类。他们能写出下面的代码:
这类情况下它可以正常运行,但是假设你想捕捉的文本包括有你分隔的公共字符(这类情况下比如;),这将会带来很***烦。假设你使用了宽松数目词,你只要花上很少的时间组装字符种类便可以产生新的正则表达式。
在你知道你要捕捉文本的环境结构时,宽松数目词是具有很大价值的。
5、利用可用分界符
Perl 和PHP语言常常使用左斜线(/)来标志1个正则表达式的开头和结尾,Python语言使用1组引号来标志开头和结尾。假设在Perl和PHP中坚持使用左斜线,你将要避免表达式中的任何斜线;假设在Python中使用引号,你将要避免使用反斜线(\)。选择不同的分界符或引号可以答应你避免1半的正则表达式。这将使得表达式易于浏览,减少由于忘记避免符号而潜伏的bug。
Perl和PHP语言答应使用任何非数字和空格字符作为分界符。假设你切换到1个新的分界符,在匹配URL或HTML标志(如“http://”或“
;”)时,你便可以够避免遗漏左斜线了。
例如,“/http:\/\/(\S)*/”可以写为“#http://(\S)*#”。
通用分界符是“#”、“!”和“|”。假设你要使用方括号、尖括号或花括号,只要保持前后配对出现便可以够了。下面就是1些通用分界符的示例:
#…# !…! {…} s|…|…| (Perl only) s[…][…] (Perl only) s<…>;/…/ (Perl only)
在Python中,正则表达式首先会被当作1个字符串。假设你使用引号作为分界符,你将遗漏所有反斜线。但是你可使用“r''”字符串避免这个题目。假设针对“re.VERBOSE”选项使用3个连续单引号,它将答应你包括换行。例如 regex = "(file://w+)(//d+)"可以写出下面的情势:
regex = r'''
(\w+)
(\d+)
'''
小结
本文的建议主要着眼于正则表达式的可读性,在开发中养成这些习惯,你将会更加清楚的考虑设计和表达式的结构,这将有助于减少bug和代码的保护,假设你自己就是这个代码的保护者你将倍感轻松。
上1页 1 2 唐山网站建设www.fw8.netTAG:代码,空格,圆括号,文本,电话号码
评论加载中...
|