一個正則運算式是一個特定的格式化模式,可以用來找出一個字串在另一個字串中的使用情況。幾個編程語言,包括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中簡單的字串。