一个正则运算式是一个特定的格式化模式,可以用来找出一个字串在另一个字串中的使用情况。几个编程语言,包括Visual Basic,Perl,javascript和PHP都支持正则运算式,希望在这篇入门指导的结束,Mitch#ll(作者自己)可以让你在PHP程式中能应用一些基本的正则运算式。正则运算式是在各种各样的程式语言中突出的古怪特征中的一种,但是由于它们看起来是很难的一个概念,所以很多开发者就把它们放到了角落里,忘记了它们的存在。
让我们先来看看什么是正则运算式,为什么你要在PHP程式中用到它们。
什么是正则运算式?
你对从一个不错的老的基于控制的文本编辑器中分离出像BBEdit和notepad的程式,有什么看法呢?两个都支援文本输入,可以让你保存文本到档中,但是现在的文本编辑器也支援其他功能,包括查找–代替工具,这让编辑一个文字档案相当容易。
正则运算式也是相似的,只是更好一些。正则运算式可以被认为一个极其高级的查找-替换工具,让我们从痛苦中摆脱出来:不必再写定制的资料确认例子来检查电子邮件位址或者来确认电话号码的格式是正确的,如此等等。
任何程式中最普通的函数之一就是资料有效性检查,PHP捆绑了一些文本检查函数,允许我们用正则运算式匹配一个字串,确认有一个空格,有一个问号,等等。
你不知道的可能是,正则运算式可以简单装备吗,当你掌握了一些正则运算式时(这个正则运算式可以用来告诉正则运算式引擎一个字串中我们想要匹配的部分),你会自问为什么会把正则运算式扔到角落里这么久,^_^。
PHP有两套函数,用来处理两种类型的正则运算式:Perl5相容模式,和Posix标准相容模式。在这篇文章中我们将看看ereg函数,用遵照Posix标准的搜索运算式工作。虽然它们并没有Perl5模式那样强大,但是一种不错的学习正则运算式的方法。如果你对PHP支援的Perl5相容正则运算式感兴趣,可以到PHP.net网站找一些关于preg函数的细节。
PHP有六个函数来处理正则运算式,它们都把一个正则运算式作为它们的第一个参数,列出如下:
• ereg: 最常用的正则运算式函数, ereg 允许我们搜索跟一个正则运算式匹配的一个字串.
• ereg_replace: 允许我们搜索跟正则运算式匹配的一个字串,并用新的字串代替所有这个运算式出现的地方。
• eregi: 和ereg几乎是一样效果,不过忽略大小写。
• eregi_replace: 和ereg_replace有着一样的搜索-替换功能,不过忽略大小写.
• split: 允许我们搜索和正则运算式匹配的字串,并且以字串集合的方式返回匹配结果.
• spliti: split函数忽略大小写的版本.
为什么使用正则运算式?
如果你不断地建立不同的函数来检查或者操作字串的一部分,现在你可能要放弃所有的这些函数,取而代之的用正则运算式。如果你对下列的问题都答“是的”,那么你肯定要考虑使用正则运算式了:
• 你是否正在写一些定制的函数来检查表单数据(比如在电子信箱位址中的一个@,一个点)?
• 你是否写一些定制的函数,在一个字串中回圈每个字元,如果这个字元匹配了一个特定特征(比如它是大写的,或者它是一个空格),那么就替换它?
除了是令人不舒服的字串检查和操作方法,如果没有有效率地写代码,上述的两条也会使你的程式慢下来。你是否更倾向于用下面的代码检查一个电子信箱地址呢:
<?php
function validateEmail($email)
{
$hasAtSymbol = strpos($email, "@");
$hasDot = strpos($email, ".");
if($hasAtSymbol && $hasDot)
return true;
else
return false;
}
echo validateEmail("mitch#
ll@devarticles.com");
?>
... 或者使用下面的代码:
<?php
function validateEmail($email)
{
return ereg("^[a-zA-Z]+@[a-zA-Z]+\.[a-zA-Z]+$", $email);
}
echo validateEmail("mitch#
ll@devarticles.com");
?>
可以肯定的是,第一个函数比较容易,而且看起来结构也不错。但是如果我们用上面的下一个版本的email位址检查函数不是更容易吗?
上面展示的第二个函数只用了正则运算式,包括了对ereg函数的一个调用。Ereg 函数返回true或者false,来声明它的字串参数是否和正则运算式相匹配。
很多编程者避开正则运算式,只因为它们(在一些情况下)比其他的文本处理方法更慢。正则运算式可能慢的原因是因为它们涉及把字串在记忆体中拷贝和粘贴,因为正则运算式的每一个新的部分都对应匹配一个字串。但是,从我对正则运算式的经验来说,除非你在文本中几百个行运行一个复杂的正则运算式,否则性能上的缺陷都可以忽略不计,当把正则运算式作为输入资料检查工具时,也很少出现这种情况。
正则运算式语法
在你可以匹配一个字串到正则运算式之前,你必须先建立正则运算式。开始的时候,正则运算式的语法有点古怪,运算式中的每一个短语代表某个类型的搜索特征。下列是一些最普通的正则运算式,也都对应着一个如何使用它的例子:
字串头部
搜索一个字串的头部,用^,例如
<?php echo ereg("^h#llo", "h#llo world!"); ?>
将返回 true, 但是
<?php echo ereg("^h#llo", "i say h#llo world"); ?>
将返回 false, 因为h#llo不在字串”I say h#llo world”的头部。
字串尾部
搜索字串尾部,用$,例如:
<?php echo ereg("bye$", "goodbye"); ?>
将返回true, 但是
<?php echo ereg("bye$", "goodbye my friend"); ?>
将返回 false,因为bye不在字串”goodbye my friend”的尾部.
任意的单个字元
搜索任意字元,用点(.),例如:
<?php echo ereg(".", "cat"); ?>
将返回true,但是
<?php echo ereg(".", ""); ?>
将返回false,因为我们的要搜索字串没有包含字元。你可以用花括弧随意告诉正则运算式引擎它要匹配多少个单个字元。如果我只想匹配5个字元,我可以这样用ereg:
<?php echo ereg(".$", "12345"); ?>
上面的这段代码告诉正则运算式引擎当且仅当至少5个连续的字元出现字串的尾部时返回true.我们也可以限制连续出现的字元的数目:
<?php echo ereg("a$", "aaa"); ?>
在上面的例子里,我们已经告诉正则运算式引擎,我们的搜索字串来匹配运算式,它在尾部必须有介于1和3个的”a”字元。
<?php echo ereg("a$", "aaab"); ?>
上面的例子将不会返回true,虽然有三个”a”字元在搜索字串里,但是它们不是在字串的尾部。如果我们把结尾字串匹配$从正则运算式中去掉,那么这个字串是匹配的。
我们也可以告诉正则运算式引擎来匹配至少有确定数目的字元在一行,如果它们存在的,可以匹配更多。 我们可以这样做:
<?php echo ereg("a$", "aaaa"); ?>
[2]
零或多次重复字元
为了告诉正则运算式引擎一个字元可能存在,也可以重复,我们用*字元。这里的两个例子都将返回true.
<?php echo ereg("t*", "tom"); ?>
<?php echo ereg("t*", "fom"); ?>
即使第二个例子不包含”t”这个字元,但仍旧返回ture,因为*表示字元可以出现,但不是必须出现。事实上,任何普通的字串模式都会使上面的ereg调用返回true,因为’t’字元是可选的.
一或多次重复字元
为了告诉正则运算式引擎一个字元必须存在,也可以重复不止一次,我们用+字元,像
<?php echo ereg("z+", "i like the zoo"); ?>
下面的例子也会返回true:
<?php echo ereg("z+", "i like the zzzzzzoo!"); ?>
零或一次重复字元
我们也可以告诉正则运算式引擎,一个字元必须是或者只存在一次,或者没有。我们用?字元来做这项工作,就像
<?php echo ereg("c?", "cats are fuzzy"); ?>
如果我们愿意,我们完全可以从上面的搜索字串中删除’c’,这个运算式会仍旧返回true.’?’ 的意思是一个’c’可以出现在搜索字串的任何地方,但不是必须的。
正则运算式语法 (contd.)
空格字元
为了匹配一个搜索字串中的空格字元,我们用预定义Posix的类,[[:space]].方括号标明连续字元的相关性,”:space:”是实际要匹配的类(在这种情形下,是任何空白字元)。空白包括tab字元,新行字元,空白字元。或者,如果搜索字串必须包含只有一个空格,而不是一个tab或者新行字元,你可以用一个空格字元(" ")。在大多数情况下,我倾向于使用":space:",因为这意味着我的意图不仅仅是单个空格字元,这点很容易被忽视。这里有一些Posix-标准预定义类,
有一些我们可以作为正则运算式的部分的一些Posix-标准预定义类,包括[:alnum:], [:digit:], [:lower:]等等。 完整的列表可以在这里查看
我们可以像这样匹配单个空白字元:
<?php echo ereg("Mitch#ll[[:space:]]Harper", "Mitch#ll Harper"); ?>
我们也可以通过在运算式后用?字元来告诉正则运算式引擎匹配没有空白或者一个空白。
<?php echo ereg("Mitch#ll[[:space:]]?Harper", "Mitch#llHarper"); ?>
模式分组
相关的模式可以在方括号里分在一起。很容易用[a-z]和[A-Z]指定只有一个小写字母或者一列大写字母以搜索字串的一部分存在。
<?php
// 要求从第一个到最后一个都是小写字母
echo ereg("^[a-z]+$", "johndoe"); // 返回true
?>
或者像
<?php
// 要求从第一个到最后一个都是大写字母
ereg("^[A-Z]+$", "JOHNDOE"); // 返回 true?
?>
我们也可以告诉正则运算式引擎,我们希望或者是小写字母,或者是大写字母。我们只要把[a-z]和[A-Z]模式结合在一起就可以做到。
<?php echo ereg("^[a-zA-Z]+$", "JohnDoe"); ?>
在上面的例子里,如果我们能匹配"John Doe",而不是"JohnDoe",将是非常有意义的。我们用下面的正则运算式来做这个:
^[a-zA-Z]+[[:space:]][a-zA-Z]+$
很容易搜索一个数位字串
<?php echo ereg("^[0-9]+$", "12345"); ?>
词语分组
不仅仅搜索模式可以分组,我们也可以用圆括号把相关的搜索词语进行分组。
<?php echo ereg("^(John|Jane).+$", "John Doe"); ?>
在上面的例子中,我们有一个字串头部字元,紧跟着"John"或者"Jane",至少有一个其他字元,然后一个字串尾部字元。所以…
<?php echo ereg("^(John|Jane).+$", "Jane Doe"); ?>
...将也匹配我们的搜索模式
特殊字元的情形
因为一些字元要用在一个搜索模式的明确分组或者语法上,像在(John|Jane)中的圆括号,我们需要告诉正则运算式引擎来遮罩这些字元,加工它们使之成为被搜索字串的一部分,而不是搜索运算式的一部分。我们所用的方法称为“字元转义”,涉及到将任何“专用符号”加上反斜杠。所以,例如,如果我想在我的搜索中包含’|’,那么我就可以这样做
<?php echo ereg("^[a-zA-z]+\|[a-zA-z]+$", "John|Jane"); ?>
这里只是少量的一些你要转义的字元,你必须转义^, $, (, ), ., [, |, *, ?, +, \ and { 。
希望你现在对正则运算式实际上有多么强大有了一点点感觉了。现在让我们看两个用正则运算式来检查资料中一个字串的例子。
正则运算式例子
例子1 (www\.)?.+\.(com|net|org)$
把所有的东西放在一起,我们的正则运算式就可以用作检查一个功能变数名称,如:
<?php
function isValidDomain($domainName)
{
return ereg("^(http|ftp)://(www\.)?.+\.(com|net|org)$", $domainName);
}
//真(true)
echo isValidDomain("
http://www.somesi...");
//真(true)
echo isValidDomain("
ftp://somesite...quot;);
//假 (false)
echo isValidDomain("
ftp://www.somes...");
//假 (false)
echo isValidDomain("
somesite.com"...);
?>
例子二
因为我居住在澳大利亚悉尼,让我们检查一个典型的澳大利亚国际电话号码。澳大利亚国际电话号码的格式如下:
+61x xxxx-xxxx
第一个x是区号,其他的都是电话号码。检查以'+61'开头且紧跟一个在2到9之间的区号的电话号码,我们用下面的正则运算式:
^\+61[2-9][[:space:]]
注意,上面的搜索模式把'+'字元用'\'转义,以便于可以在搜索中包含,不至于被解释为一个正则运算式。[2-9]告诉正则运算式引擎我们需要包含一个2到9之间的数字。[[:space:]]类则告诉正则运算式期望在这里有一个空白。
这里是电话号码剩下的搜索模式:
[0-9]-[0-9]$
这里没有什么不寻常的地方,我们只是告诉正则运算式引擎电话号码可用的数位,它必须是4个数位的组合,跟着一个连接符,再跟着另一个4个数位的组合,然后一个字串尾部字元。
把完整的正则运算式放在一起,放进一个函数,我们可以用代码来检查一些澳大利亚国际电话号码:
<?php
function isValidPhone($phoneNum)
{
echo ereg("^\+61[2-9][[:space:]][0-9]-[0-9]$", $phoneNum);
}
// 真(true)
echo isValidPhone("+619 0000-0000");
// 假(false)
echo isValidPhone("+61 00000000");
//假( false)
echo isValidPhone("+611 00000000");
?>
总结
正则运算式用一些不适合书写和重复的代码来检查一个字串。在最后的几页里,我们已经讲解了所有的Posix标准正则运算式的基础,包括字元,分组和PHP ereg函数。我们也知道了怎么用正则运算式来检查一些PHP中简单的字串。