PHP與正則表達(dá)式
發(fā)表時(shí)間:2024-06-11 來源:明輝站整理相關(guān)軟件相關(guān)文章人氣:
[摘要]原作者:Mitchell Harper 翻譯:iwind原文:http://www.devarticles.com/c/a/PHP/PHP-and-Regular-Expressions-101 一個(gè)正則表達(dá)式是一個(gè)特定的格式化模式,可以用來找出一個(gè)字符串在另一個(gè)字符串中的使用情況。幾個(gè)編程語言...
原作者:Mitchell Harper 翻譯:iwind
原文:http://www.devarticles.com/c/a/PHP/PHP-and-Regular-Expressions-101
一個(gè)正則表達(dá)式是一個(gè)特定的格式化模式,可以用來找出一個(gè)字符串在另一個(gè)字符串中的使用情況。幾個(gè)編程語言,包括Visual Basic,Perl,JavaScript和PHP都支持正則表達(dá)式,希望在這篇入門指導(dǎo)的結(jié)束,Mitchell(作者自己)可以讓你在PHP程序中能應(yīng)用一些基本的正則表達(dá)式。正則表達(dá)式是在各種各樣的程序語言中突出的古怪特征中的一種,但是由于它們看起來是很難的一個(gè)概念,所以很多開發(fā)者就把它們放到了角落里,忘記了它們的存在。
讓我們先來看看什么是正則表達(dá)式,為什么你要在PHP程序中用到它們。
什么是正則表達(dá)式?
你對(duì)從一個(gè)不錯(cuò)的老的基于控制的文本編輯器中分離出像BBEdit和notepad的程序,有什么看法呢??jī)蓚(gè)都支持文本輸入,可以讓你保存文本到文件中,但是現(xiàn)在的文本編輯器也支持其它功能,包括查找–代替工具,這讓編輯一個(gè)文本文件相當(dāng)容易。
正則表達(dá)式也是相似的,只是更好一些。正則表達(dá)式可以被認(rèn)為一個(gè)極其高級(jí)的查找-替換工具,讓我們從痛苦中擺脫出來:不必再寫定制的數(shù)據(jù)確認(rèn)例子來檢查電子郵件地址或者來確認(rèn)電話號(hào)碼的格式是正確的,如此等等。
任何程序中最普通的函數(shù)之一就是數(shù)據(jù)有效性檢查,PHP捆綁了一些文本檢查函數(shù),允許我們用正則表達(dá)式匹配一個(gè)字符串,確認(rèn)有一個(gè)空格,有一個(gè)問號(hào),等等。
你不知道的可能是,正則表達(dá)式可以簡(jiǎn)單裝備嗎,當(dāng)你掌握了一些正則表達(dá)式時(shí)(這個(gè)正則表達(dá)式可以用來告訴正則表達(dá)式引擎一個(gè)字符串中我們想要匹配的部分),你會(huì)自問為什么會(huì)把正則表達(dá)式扔到角落里這么久,^_^。
PHP有兩套函數(shù),用來處理兩種類型的正則表達(dá)式:Perl5兼容模式,和Posix標(biāo)準(zhǔn)兼容模式。在這篇文章中我們將看看ereg函數(shù),用遵照Posix標(biāo)準(zhǔn)的搜索表達(dá)式工作。雖然它們并沒有Perl5模式那樣強(qiáng)大,但是一種不錯(cuò)的學(xué)習(xí)正則表達(dá)式的方法。如果你對(duì)PHP支持的Perl5兼容正則表達(dá)式感興趣,可以到PHP.net網(wǎng)站找一些關(guān)于preg函數(shù)的細(xì)節(jié)。
PHP有六個(gè)函數(shù)來處理正則表達(dá)式,它們都把一個(gè)正則表達(dá)式作為它們的第一個(gè)參數(shù),列出如下:
ereg: 最常用的正則表達(dá)式函數(shù), ereg 允許我們搜索跟一個(gè)正則表達(dá)式匹配的一個(gè)字符串.
ereg_replace: 允許我們搜索跟正則表達(dá)式匹配的一個(gè)字符串,并用新的字符串代替所有這個(gè)表達(dá)式出現(xiàn)的地方。
eregi: 和ereg幾乎是一樣效果,不過忽略大小寫。
eregi_replace: 和ereg_replace有著一樣的搜索-替換功能,不過忽略大小寫.
split: 允許我們搜索和正則表達(dá)式匹配的字符串,并且以字符串集合的方式返回匹配結(jié)果.
spliti: split函數(shù)忽略大小寫的版本.
為什么使用正則表達(dá)式?
如果你不斷地建立不同的函數(shù)來檢查或者操作字符串的一部分,現(xiàn)在你可能要放棄所有的這些函數(shù),取而代之的用正則表達(dá)式。如果你對(duì)下列的問題都答“是的”,那么你肯定要考慮使用正則表達(dá)式了:
你是否正在寫一些定制的函數(shù)來檢查表單數(shù)據(jù)(比如在電子信箱地址中的一個(gè)@,一個(gè)點(diǎn))?
你是否寫一些定制的函數(shù),在一個(gè)字符串中循環(huán)每個(gè)字符,如果這個(gè)字符匹配了一個(gè)特定特征(比如它是大寫的,或者它是一個(gè)空格),那么就替換它?
除了是令人不舒服的字符串檢查和操作方法,如果沒有有效率地寫代碼,上述的兩條也會(huì)使你的程序慢下來。你是否更傾向于用下面的代碼檢查一個(gè)電子信箱地址呢:
<?php
function validateEmail($email)
{
$hasAtSymbol = strpos($email, "@");
$hasDot = strpos($email, ".");
if($hasAtSymbol && $hasDot)
return true;
else
return false;
}
echo validateEmail("
[email protected]");
?>
... 或者使用下面的代碼:
<?php
function validateEmail($email)
{
return ereg("^[a-zA-Z]+@[a-zA-Z]+\.[a-zA-Z]+$", $email);
}
echo validateEmail("
[email protected]");
?>
可以肯定的是,第一個(gè)函數(shù)比較容易,而且看起來結(jié)構(gòu)也不錯(cuò)。但是如果我們用上面的下一個(gè)版本的email地址檢查函數(shù)不是更容易嗎?
上面展示的第二個(gè)函數(shù)只用了正則表達(dá)式,包括了對(duì)ereg函數(shù)的一個(gè)調(diào)用。Ereg 函數(shù)返回true或者false,來聲明它的字符串參數(shù)是否和正則表達(dá)式相匹配。
很多編程者避開正則表達(dá)式,只因?yàn)樗鼈儯ㄔ谝恍┣闆r下)比其它的文本處理方法更慢。正則表達(dá)式可能慢的原因是因?yàn)樗鼈兩婕鞍炎址趦?nèi)存中拷貝和粘貼,因?yàn)檎齽t表達(dá)式的每一個(gè)新的部分都對(duì)應(yīng)匹配一個(gè)字符串。但是,從我對(duì)正則表達(dá)式的經(jīng)驗(yàn)來說,除非你在文本中幾百個(gè)行運(yùn)行一個(gè)復(fù)雜的正則表達(dá)式,否則性能上的缺陷都可以忽略不計(jì),當(dāng)把正則表達(dá)式作為輸入數(shù)據(jù)檢查工具時(shí),也很少出現(xiàn)這種情況。
正則表達(dá)式語法
在你可以匹配一個(gè)字符串到正則表達(dá)式之前,你必須先建立正則表達(dá)式。開始的時(shí)候,正則表達(dá)式的語法有點(diǎn)古怪,表達(dá)式中的每一個(gè)短語代表某個(gè)類型的搜索特征。下列是一些最普通的正則表達(dá)式,也都對(duì)應(yīng)著一個(gè)如何使用它的例子:
字符串頭部
搜索一個(gè)字符串的頭部,用^,例如
<?php echo ereg("^hello", "hello world!"); ?>
將返回 true, 但是
<?php echo ereg("^hello", "i say hello world"); ?>
將返回 false, 因?yàn)閔ello不在字符串”I say hello world”的頭部。
字符串尾部
搜索字符串尾部,用$,例如:
<?php echo ereg("bye$", "goodbye"); ?>
將返回true, 但是
<?php echo ereg("bye$", "goodbye my friend"); ?>
將返回 false,因?yàn)閎ye不在字符串”goodbye my friend”的尾部.
任意的單個(gè)字符
搜索任意字符,用點(diǎn)(.),例如:
<?php echo ereg(".", "cat"); ?>
將返回true,但是
<?php echo ereg(".", ""); ?>
將返回false,因?yàn)槲覀兊囊阉髯址疀]有包含字符。你可以用花括號(hào)隨意告訴正則表達(dá)式引擎它要匹配多少個(gè)單個(gè)字符。如果我只想匹配5個(gè)字符,我可以這樣用ereg:
<?php echo ereg(".{5}$", "12345"); ?>
上面的這段代碼告訴正則表達(dá)式引擎當(dāng)且僅當(dāng)至少5個(gè)連續(xù)的字符出現(xiàn)字符串的尾部時(shí)返回true.我們也可以限制連續(xù)出現(xiàn)的字符的數(shù)目:
<?php echo ereg("a{1,3}$", "aaa"); ?>
在上面的例子里,我們已經(jīng)告訴正則表達(dá)式引擎,我們的搜索字符串來匹配表達(dá)式,它在尾部必須有介于1和3個(gè)的”a”字符。
<?php echo ereg("a{1,3}$", "aaab"); ?>
上面的例子將不會(huì)返回true,雖然有三個(gè)”a”字符在搜索字符串里,但是它們不是在字符串的尾部。如果我們把結(jié)尾字符串匹配$從正則表達(dá)式中去掉,那么這個(gè)字符串是匹配的。
我們也可以告訴正則表達(dá)式引擎來匹配至少有確定數(shù)目的字符在一行,如果它們存在的,可以匹配更多。 我們可以這樣做:
<?php echo ereg("a{3,}$", "aaaa"); ?>
零或多次重復(fù)字符
為了告訴正則表達(dá)式引擎一個(gè)字符可能存在,也可以重復(fù),我們用*字符。這里的兩個(gè)例子都將返回true.
<?php echo ereg("t*", "tom"); ?>
<?php echo ereg("t*", "fom"); ?>
即使第二個(gè)例子不包含”t”這個(gè)字符,但仍舊返回ture,因?yàn)?表示字符可以出現(xiàn),但不是必須出現(xiàn)。事實(shí)上,任何普通的字符串模式都會(huì)使上面的ereg調(diào)用返回true,因?yàn)椤痶’字符是可選的.
一或多次重復(fù)字符
為了告訴正則表達(dá)式引擎一個(gè)字符必須存在,也可以重復(fù)不止一次,我們用+字符,像
<?php echo ereg("z+", "i like the zoo"); ?>
下面的例子也會(huì)返回true:
<?php echo ereg("z+", "i like the zzzzzzoo!"); ?>
零或一次重復(fù)字符
我們也可以告訴正則表達(dá)式引擎,一個(gè)字符必須是或者只存在一次,或者沒有。我們用?字符來做這項(xiàng)工作,就像
<?php echo ereg("c?", "cats are fuzzy"); ?>
如果我們?cè)敢猓覀兺耆梢詮纳厦娴乃阉髯址袆h除’c’,這個(gè)表達(dá)式會(huì)仍舊返回true.’?’ 的意思是一個(gè)’c’可以出現(xiàn)在搜索字符串的任何地方,但不是必須的。
正則表達(dá)式語法 (續(xù))
空格字符
為了匹配一個(gè)搜索字符串中的空格字符,我們用預(yù)定義Posix的類,[[:space]].方括號(hào)標(biāo)明連續(xù)字符的相關(guān)性,”:space:”是實(shí)際要匹配的類(在這種情形下,是任何空白字符)。空白包括tab字符,新行字符,空白字符。或者,如果搜索字符串必須包含只有一個(gè)空格,而不是一個(gè)tab或者新行字符,你可以用一個(gè)空格字符(" ")。在大多數(shù)情況下,我傾向于使用":space:",因?yàn)檫@意味著我的意圖不僅僅是單個(gè)空格字符,這點(diǎn)很容易被忽視。這里有一些Posix-標(biāo)準(zhǔn)預(yù)定義類,
有一些我們可以作為正則表達(dá)式的部分的一些Posix-標(biāo)準(zhǔn)預(yù)定義類,包括[:alnum:], [:digit:], [:lower:]等等。 完整的列表可以在這里查看
我們可以像這樣匹配單個(gè)空白字符:
<?php echo ereg("Mitchell[[:space:]]Harper", "Mitchell Harper"); ?>
我們也可以通過在表達(dá)式后用?字符來告訴正則表達(dá)式引擎匹配沒有空白或者一個(gè)空白。
<?php echo ereg("Mitchell[[:space:]]?Harper", "MitchellHarper"); ?>
模式分組
相關(guān)的模式可以在方括號(hào)里分在一起。很容易用[a-z]和[A-Z]指定只有一個(gè)小寫字母或者一列大寫字母以搜索字符串的一部分存在。
<?php
// 要求從第一個(gè)到最后一個(gè)都是小寫字母
echo ereg("^[a-z]+$", "johndoe"); // 返回true
?>
或者像
<?php
// 要求從第一個(gè)到最后一個(gè)都是大寫字母
ereg("^[A-Z]+$", "JOHNDOE"); // 返回 true?
?>
我們也可以告訴正則表達(dá)式引擎,我們希望或者是小寫字母,或者是大寫字母。我們只要把[a-z]和[A-Z]模式結(jié)合在一起就可以做到。
<?php echo ereg("^[a-zA-Z]+$", "JohnDoe"); ?>
在上面的例子里,如果我們能匹配"John Doe",而不是"JohnDoe",將是非常有意義的。我們用下面的正則表達(dá)式來做這個(gè):
^[a-zA-Z]+[[:space:]]{1}[a-zA-Z]+$
很容易搜索一個(gè)數(shù)字字符串
<?php echo ereg("^[0-9]+$", "12345"); ?>
詞語分組
不僅僅搜索模式可以分組,我們也可以用圓括號(hào)把相關(guān)的搜索詞語進(jìn)行分組。
<?php echo ereg("^(John Jane).+$", "John Doe"); ?>
在上面的例子中,我們有一個(gè)字符串頭部字符,緊跟著"John"或者"Jane",至少有一個(gè)其它字符,然后一個(gè)字符串尾部字符。所以…
<?php echo ereg("^(John Jane).+$", "Jane Doe"); ?>
...將也匹配我們的搜索模式
特殊字符的情形
因?yàn)橐恍┳址迷谝粋(gè)搜索模式的明確分組或者語法上,像在(John Jane)中的圓括號(hào),我們需要告訴正則表達(dá)式引擎來屏蔽這些字符,加工它們使之成為被搜索字符串的一部分,而不是搜索表達(dá)式的一部分。我們所用的方法稱為“字符轉(zhuǎn)義”,涉及到將任何“專用符號(hào)”加上反斜杠。所以,例如,如果我想在我的搜索中包含’ ’,那么我就可以這樣做
<?php echo ereg("^[a-zA-z]+\ [a-zA-z]+$", "John Jane"); ?>
這里只是少量的一些你要轉(zhuǎn)義的字符,你必須轉(zhuǎn)義^, $, (, ), ., [, , *, ?, +, \ and { 。
希望你現(xiàn)在對(duì)正則表達(dá)式實(shí)際上有多么強(qiáng)大有了一點(diǎn)點(diǎn)感覺了。現(xiàn)在讓我們看兩個(gè)用正則表達(dá)式來檢查數(shù)據(jù)中一個(gè)字符串的例子。
正則表達(dá)式例子
例子1
讓我們把第一個(gè)例子做的相當(dāng)簡(jiǎn)單,檢驗(yàn)一個(gè)標(biāo)準(zhǔn)的URL.一個(gè)標(biāo)準(zhǔn)的URL(沒有端口號(hào)),有三個(gè)部分構(gòu)成:
[協(xié)議]://[域名]
讓我們從匹配URL的協(xié)議部分開始,并且讓它只能用http或者ftp.我們可以用下面的正則表達(dá)式做到這點(diǎn):
^(http ftp)
^字符特指字符串的頭部,利用圓括號(hào)把http和ftp圍住,且用“或者”符號(hào)( )將它們分開,我們告訴正則表達(dá)式引擎http和ftp兩者之一必須在字符串的開頭。
一個(gè)域名通常由www.somesite.com構(gòu)成,但是可以隨意選擇要不要www部分。為了例子簡(jiǎn)單,我們只允許.com,.net,和.org的域名是在考慮之中的。我們最好這樣對(duì)正則表達(dá)式中的域名部分表示如下:
(www\.)?.+\.(com net org)$
把所有的東西放在一起,我們的正則表達(dá)式就可以用作檢查一個(gè)域名,如:
<?php
function isValidDomain($domainName)
{
return ereg("^(http ftp)://(www\.)?.+\.(com net org)$", $domainName);
}
//真(true)
echo isValidDomain("http://www.somesite.com");
//真(true)
echo isValidDomain("ftp://somesite.com");
//假 (false)
echo isValidDomain("ftp://www.somesite.fr");
//假 (false)
echo isValidDomain("www.somesite.com");
?>
例子二
因?yàn)槲揖幼≡诎拇罄麃喯つ幔屛覀儥z查一個(gè)典型的澳大利亞國(guó)際電話號(hào)碼。澳大利亞國(guó)際電話號(hào)碼的格式如下:
+61x xxxx-xxxx
第一個(gè)x是區(qū)號(hào),其它的都是電話號(hào)碼。檢查以'+61'開頭且緊跟一個(gè)在2到9之間的區(qū)號(hào)的電話號(hào)碼,我們用下面的正則表達(dá)式:
^\+61[2-9][[:space:]]
注意,上面的搜索模式把'+'字符用'\'轉(zhuǎn)義,以便于可以在搜索中包含,不至于被解釋為一個(gè)正則表達(dá)式。[2-9]告訴正則表達(dá)式引擎我們需要包含一個(gè)2到9之間的數(shù)字。[[:space:]]類則告訴正則表達(dá)式期望在這里有一個(gè)空白。
這里是電話號(hào)碼剩下的搜索模式:
[0-9]{4}-[0-9]{4}$
這里沒有什么不尋常的地方,我們只是告訴正則表達(dá)式引擎電話號(hào)碼可用的數(shù)字,它必須是4個(gè)數(shù)字的組合,跟著一個(gè)連接符,再跟著另一個(gè)4個(gè)數(shù)字的組合,然后一個(gè)字符串尾部字符。
把完整的正則表達(dá)式放在一起,放進(jìn)一個(gè)函數(shù),我們可以用代碼來檢查一些澳大利亞國(guó)際電話號(hào)碼:
<?php
function isValidPhone($phoneNum)
{
echo ereg("^\+61[2-9][[:space:]][0-9]{4}-[0-9]{4}$", $phoneNum);
}
// 真(true)
echo isValidPhone("+619 0000-0000");
// 假(false)
echo isValidPhone("+61 00000000");
//假( false)
echo isValidPhone("+611 00000000");
?>
總結(jié)
正則表達(dá)式用一些不適合書寫和重復(fù)的代碼來檢查一個(gè)字符串。在最后的幾頁里,我們已經(jīng)講解了所有的Posix標(biāo)準(zhǔn)正則表達(dá)式的基礎(chǔ),包括字符,分組和PHP ereg函數(shù)。我們也知道了怎么用正則表達(dá)式來檢查一些PHP中簡(jiǎn)單的字符串。
譯者注釋:本人英文不怎么好,可能一些地方有出入。本文中的字符類其實(shí)是我們所說的字符簇。