Regex在PHP中的正確使用方法指導

來源:互聯網
上載者:User
Regex提供了一種處理文本的強大方法。使用Regex,您可以對使用者輸入進行複雜的檢驗、解析使用者輸入和檔案內容,以及重新格式化字串。PHP 為使用者提供了使用 POSIX 和 PCRE Regex的簡單方法。本教程將討論 POSIX 和 PCRE 之間的差異,並介紹如何使用Regex和 PHP V5。

開始之前

瞭解通過本教程可學到哪些內容以及如何更好地利用本教程。

關於本教程

Regex提供了一種處理文本的強大方法。使用Regex,您可以對使用者輸入進行複雜的檢驗、解析使用者輸入和常值內容,以及重新格式化字串。

目標

本教程將集中介紹使用 POSIX 和 PCRE Regex的簡單方法,使您熟練掌握 PHP 的Regex。我們將探討 POSIX 和 PCRE 之間的差異,還會介紹如何使用Regex和 PHP V5。通過學習本教程,您將瞭解使用Regex的方法、時機和理由。

系統需求

您可以在任何安裝了 PHP 的類 Microsoft Windows 或類 UNIX 系統(包括 Mac OS X 和 Linux)上完成本教程。由於我們所介紹的內容均為 PHP 內建外掛程式,因此只需在系統中安裝 PHP 即可,無需安裝其他軟體。

開始

何為Regex?

幾年前,我對 Web 表單的輸入框做了一些有趣的檢驗。使用者將在此表單中輸入電話號碼。隨後,此電話號碼會按使用者鍵入的形式列印在使用者的廣告中。按照要求,美國的電話號碼可以幾種方式輸入:可以是 (555) 555-5555,也可以是 555-555-5555,但不能接受 555-5555 這樣的形式。

您或許會感到奇怪,為什麼我們不拋開所有的非數字字元,只保證剩餘的字元總數為 10 呢?這種方法確實可行,但無法阻止使用者輸入 !555?333-3333 這樣的內容。

以一名 Web 開發人員的眼光來看,這種情況帶來了一項有趣的挑戰。我可以編寫常式來檢查各種不同格式,但我希望能夠找到一種解決方案,假如使用者隨後認可 555.555.5555 這樣的格式,這種解決方案能具備一定的靈活性。

這正是Regex(簡稱為 regex)的適用情境。之前我已經將它們剪下並粘貼到了應用程式中,但從未發現任何難以理解的文法問題。Regex 看上去非常像數學運算式。當您看到一個形如 2x2=4 的運算式時,您通常會想到 “2 乘以 2 等於 4”。Regex與之非常類似。閱讀過本文後,當您看到一個這樣的Regex ^b$ 時,您就會告訴自己:“一行的開頭是 b,隨後就是行尾”。不僅如此,您還會意識到在 PHP 中使用Regex有多麼簡單。

使用 regex 的時機

在有規則可循時,您應使用 regex 來完成搜尋和替換操作,但不必具有需要找到或替換的確切字元。舉例來說,在上文中提到的電話號碼的例子中,使用者定義了表明所輸入電話號碼的格式的規則,但並未定義電話號碼中所包含的數字。這同樣適用於有大批使用者輸入的情境。美國州名縮寫可限制為兩個從 A 到 Z 的大寫字母。這裡也可使用Regex,您可簡單地將表單中的文本或使用者輸入限制為字母表中的字母,而無需考慮大小寫和長度問題。

不宜使用 regex 的時機

Regex功能強大,但也有一些缺陷。其中之一就是要求具備讀寫運算式的相關技能。如果您決定在應用程式中包含Regex,就應該對其進行完整的注釋。這樣,此後如果有其他人需要更改運算式,即可在不中斷功能的情況下完成更改。另外,如果您對於使用Regex不夠熟悉,可能會發現它們難於調試。

為避免出現這些難題,在更簡單的內建功能足以很好地解決問題時不要使用Regex。

POSIX 與 PCRE

PHP 支援兩種Regex的實現:Portable Operating System Implementation(POSIX)和 Perl-Compatible Regular Expression(PCRE)。這兩種實現提供了不同的特性,但它們在 PHP 中使用起來一樣簡單。您所使用的 regex 風格取決於您過去在 regex 使用方面的經驗和使用習慣。有一些證據表明,PCRE 運算式的速度比 POSIX 運算式要略微快一點,但在絕大多數應用程式中,這一差別體現得不是那麼明顯。

在本文的樣本中,各 regex 方法的文法都包含在注釋中。在函數文法中,regex 為 regex 參數,所搜尋的字串為 string。括弧中的參數是可選的,由於本教程主要介紹基礎內容,故不會給出全部選擇性參數的介紹。

Regex文法

儘管 POSIX 和 PCRE 實現在對某些特性和字元類的支援方面有所不同,但它們的文法是相同的。每個Regex都是由一個或多個字元、特殊字元(有時也稱為元字元)、字元類和字元組構成的。

POSIX 和 PCRE 使用相同的萬用字元 —— 在 regex 中以萬用字元來表示 “此處可為任意內容”。萬用字元字元為一個英文句號或點(.)。若要尋找英文句號或點,可使用逸出字元 /: /.。下文中所討論的其他特殊字元也是如此,例如行錨(line anchor)和限定符。如果一個字元在Regex中有特殊含義,那麼必須通過轉義才能表達其原本的文字含義。

行錨 是特殊的元字元,與一行的開頭和結尾相匹配,但不會捕獲任何文本(參見表 1)。例如,如果某一行以字母 a 開頭,那麼運算式 ^a 中的行錨不會捕獲字母 a,而是匹配行的開頭。


表 1. 行錨

描述
^ 匹配一行的開頭
$ 匹配一行的結尾

限定符 應用於緊接於其前的運算式(參見表 2)。使用限定符,您可以指定在一次搜尋中尋找到一個運算式的次數。例如,運算式 a+ 將一次或多次地尋找到字母 a


表 2. 限定符

限定符 描述
? 限定符之前的運算式可被尋找到 0 次或 1 次
+ 限定符之前的運算式可被尋找到 1 次或多次
* 限定符之前的運算式可被尋找到任意次(含 0 次)
{n} 限定符之前的運算式僅可被尋找到 n 次
{n,m} 限定符之前的運算式可被尋找到 n 次到 m 次之間

在 regex 中,捕獲文本並在替換和搜尋操作中引用該文本是一項非常有用的特性(參見表 3)。通過使用捕獲功能,您可以執行搜尋,來尋找重複的單詞和閉合的 HTML 及 XML 標記。如果您在替換時使用了捕獲功能,那麼可以將找回的文本置入替換字串內。後面將給出一個樣本,展示如何以超連結替換電子郵件地址。


表 3. 分組與捕獲

字元類 描述
() 分組字元,並能夠捕獲文本

POSIX 字元類

POSIX Regex遵循一些使其可為許多 regex 實現所用的標準(參見表 4)。例如,如果您正在編寫一條 POSIX Regex,您可以在 PHP 中使用它、可以通過 grep 命令使用它,也可以通過許多支援Regex的編輯器使用它。


表 4. POSIX 字元類

字元 描述
[:alpha:] 匹配包含字母與數位字元
[:digit:] 匹配任一數字
[:space:] 匹配任意空白

POSIX 匹配

有兩個使用 POSIX Regex搜尋字串的函數,即 ereg()eregi()

ereg()

ereg() 方法為特定Regex搜尋字串。如果未找到任何匹配項,則返回 0,因此您可以給出如下測試:


清單 1. ereg() 方法

<?php$phonenbr="555-555-5555";// Syntax is ereg( regex, string [, out_captures_array])if (ereg("[-[:digit:]]{12}", $phonenbr)) {    print("Found match!/n");} else {    print("No match found!/n");}?>

Regex [-[:digit:]]{12} 尋找 12 個為數字或連字號的字元。就處理電話號碼而言,這有些粗略,您也可將其改寫成這樣的形式:^[0-9]{3}-[0-9]{3}-[0-9]{4}$。(在 regex 中,[0-9][:digit:] 實際上是完全相同的,您可能更願意使用 [0-9] 的形式,因為它更短些。)這種作為替代方案的運算式顯然更為精確。它會尋找行的開頭(^),後接一組 3 個數字([0-9]{3})、一個連字號(-)、另外一組 3 個數字、另外一個連字號、一組 4 個數字,然後是行的結尾($)。當您手工編寫運算式時,這會使您瞭解到Regex要處理的問題的複雜程度如何,從而有助於預測出使用運算式搜尋或替換的資料類型。

eregi()

eregi() 方法類似於 ereg(),不同之處在於它對大小寫不敏感。它將返回一個包含所找到的匹配項長度的整數,但您很可能會將其用於條件陳述式中,如下所示:


清單 2. eregi() 方法

<?php$str="Hello World!";// Syntax is ereg( regex, string [, out_captures_array])if (eregi("hello", $str)) {    print("Found match!/n");} else {    print("No match found!/n");}?>

執行此樣本時,將輸出 Found match!,這是因為在忽略大小寫搜尋中找到了 hello。如果您使用的是 ereg,搜尋將失敗。

POSIX 替換

ereg_replace()eregi_replace() 這兩種方法用於在文本中進行替換,具有 POSIX Regex的特性。

ereg_replace()

您可以使用 ereg_replace() 方法以 POSIX Regex文法進行大小寫敏感的替換。如下樣本描述了如何替換帶有超連結的字串內的電子郵件地址:


清單 3. ereg_replace() 方法

<?php$origstr = "My e-mail address is: first.last@example.com";// Syntax is: ereg_replace( regex, replacestr, string )$newstr = /ereg_replace("([.[:alpha:][:digit:]]+@[.[:alpha:][:digit:]]+)",     "<a href=/"mailto://1/">//1</a>", $origstr);print("$newstr/n");?>

這是一條用於匹配電子郵件地址的Regex的不完整版本,但它展示了與 str_replace() 等其他普通替換函數相比,ereg_replace() 的強大之處。在使用Regex時,您可定義搜尋的規則,而不是搜尋文字字元。

eregi_replace()

除忽略大小寫之外,eregi_replace() 函數與 ereg_replace() 是完全相同的:


清單 4. eregi_replace() 函數

<?php$origstr = "1 BANANA, 2 banana, 3 Banana";// Syntax is: eregi_replace( regex, replacestr, string )$newstr = eregi_replace("banana", "pear", $origstr);print("New string is: '$newstr'/n");?>

本例將 banana 替換為 pear,替換操作忽略了大小寫。

PCRE 字元類

由於 PCRE 文法支援更短的字元類和更多的特性,因此它比 POSIX 文法更為強大。表 5 列出了 PCRE 中支援而在 POSIX 運算式中沒有的部分字元類。


表 5. PCRE 字元類

字元類 描述
/b 詞邊界,尋找詞的開始和結尾
/d 匹配任一數字
/s 匹配任意空白,如 tab 或空格
/t 匹配一個 tab 字元
/w 匹配包含字母與數位字元

PCRE 匹配

PHP 中的 PCRE 匹配函數與 POSIX 匹配函數類似,但如果您習慣使用 POSIX 運算式,那麼 PCRE 匹配函數的一項特性可能會使您感到棘手:PCRE 函數要求運算式以分隔字元開始和結束。在絕大多數樣本中,分隔字元都是一個 /,可在引號內運算式的開始和結尾處看到。務必牢記,此分隔字元並非運算式的一部分。

在 PCRE 中的最後一個分隔字元後,您可添加一個修飾符來更改Regex的行為。舉例來說,i 修飾符使Regex對大小寫不敏感。這是與 POSIX 方法的一項重要差異,在 POSIX 中,您需要按照對大小寫敏感性的需求來調用不同的方法。

preg_grep()

preg_grep() 方法返回一個數組,其中包含通過Regex在其中找到匹配項的另外一個數組的全部項目。如果您有一個較大的值集,並希望對其進行搜尋以尋找匹配項,那麼該方法非常有用。下面是一個樣本:


清單 5. preg_grep() 方法

<?php$array = array( "1", "3", "ABC", "XYZ", "42" );// Syntax is preg_grep( regex, inputarray );$grep_array = preg_grep("/^/d+$/", $array);print_r($grep_array);?>

在本例中,Regex ^/d+$ 尋找行的開始(^)和結尾($)之間包含一個或多個數字(/d+)的數組的所有元素。

preg_match()

preg_match() 函數使用 PCRE 在字串中尋找匹配項,它需要兩個參數:regex 和字串。您可以選擇提供一個將由匹配項填充的數組、允許您修改匹配操作行為的標誌,還可提供字串中開始尋找匹配項的位置(offset)。樣本如下:


清單 6. offset 方法

<?php$string = "abcdefgh";$regex = "/^[a-z]+$/i";// Syntax is preg_match(regex, string, [, out_matches [, flags [, offset]]]);if (preg_match($regex, $string)) {    printf("Pattern '%s' found in string '%s'/n", $regex, $string);} else {    printf("No match found in string '%s'!/n", $string);}?>

本例使用了Regex ^[a-z]+$,在行的開始(^)和結尾($)之間搜尋可尋找到一次或多次的([a-z]+)、從 az 的任意字母。

preg_match_all()

preg_match_all() 函數為在字串中尋找到的全部匹配項構建一個數組。下例構建了一個包含句子中全部詞的數組:


清單 7. preg_match_all() 函數

<?php$string = "The quick red fox jumped over the lazy brown dog";$re = "//b/w+/b/";// Syntax is preg_match_all( regex, string, return_array [, flags [, offset]])preg_match_all($re, $string, $arrayout);print_r($arrayout);?>

Regex /b/w+/b 在詞邊界(/b)間尋找可找到一次或多次的(/w+)單詞字元。每個詞都將置入輸出數組 $arrayout 的一個數組元素中。

PCRE 替換

在 PHP 中進行 PCRE 替換與 POSIX 替換類似,不同之處在於使用的是 preg_replace() 而非 ereg_replace()eregi_replace()

preg_replace()

preg_replace() 函數使用 PCRE 進行替換。它需要這樣幾個參數:Regex、替換運算式和原始字串。您還可以選擇提供希望的最大替換數,以及以所完成的替換數填充的變數。樣本如下:


清單 8. preg_replace() 函數

<?php$orig_string = "5555555555";printf("Original string is '%s'/n", $orig_string);$re = "/^(/d{3})(/d{3})(/d{4})$/";// Syntax is preg_replace( regex, replacement, string /[, limit [, out_count]] );$new_string = preg_replace($re, "(//1) //2-//3", $orig_string);printf("New string is '%s'/n", $new_string);?>

本例快速示範了捕獲部分文本及使用反向引用 的方法,如 //1。這些反向引用會插入圓括弧內所匹配的任意文本中,在本例中,//1 匹配第 1 組 (/d{3})

在樣本中,您可使用 substr 將電話號碼分割開來,而對字串只需進行少量更改,要依靠 substr 來可靠地捕獲正確文本會更加困難。

如果字串的形式可為 (555)5555555,您可將運算式修改為 ^(?(/d{3}))?(/d{3})(/d{4})$ 以尋找任意圓括弧。

結束語

PHP 為Regex提供了兩種文法:POSIX 和 PCRE。本教程對 PHP 中支援 POSIX 和 PCRE Regex的主要函數進行了高度概述。

使用Regex,您可以定義規則來進行更強大的搜尋和替換操作 —— 大大超越了文字的搜尋與替換。

參考資料

學習

  • 您可以參閱本文在 developerWorks 全球網站上的 英文原文。

  • Regular-Expressions.info 提供了關於Regex的相關資訊。

  • PHP: Regular Expression Functions (Perl-Compatible) - Manual 是涵蓋了 PCRE 相關內容的 PHP 線上文檔。

  • Regular Expression Functions (POSIX Extended) 是關於 POSIX 的 PHP 線上文檔。

  • 訪問 developerWorks 中的 PHP 項目資源 可擷取更多關於 PHP 的資訊。

  • 關於學習使用 PHP 編程的 developerWorks 教程,請參閱 “學習 PHP,第 1 部分” 、第 2 部分 和 第 3 部分。

  • 瞭解最新的 developerWorks 技術活動和 Webcast。

  • 訪問 developerWorks 開放源碼專區,獲得大量的 how-to 資訊、工具和項目更新,協助您使用開放源碼技術進行開發並與 IBM 產品結合使用。


獲得產品和技術

  • 通過 PHP.net 下載 最新版本的 PHP。

  • Regular Expression Library 有一個Regex的大型存放庫。

  • 訂購免費的 SEK for Linux,這是兩張 DVD,其中包含了 IBM 在 Linux 平台上的最新試用軟體,包括 DB2、Lotus、Rational、Tivoli 和 WebSphere。

  • 使用 IBM 試用軟體 革新您的下一個開放源碼項目,可通過下載或從 DVD 中獲得這些軟體。


討論

  • 通過參與 developerWorks blogs 加入 developerWorks 社區。

關於作者

Nathan A. Good 是明尼蘇達州 Twin Cities 的一位作者、軟體工程師和系統管理員。他撰寫的圖書包括與 Lee Babin 等人合著的 PHP 5 Recipes: A Problem-Solution Approach(Apress 出版社,2005 年)、Regular Expression Recipes for Windows Developers: A Problem-Solution Approach(Apress 出版社,2005 年)、Regular Expressions: A Problem-Solution Approach(Apress 出版社,2005 年)及與 Kapil Sharma 等人合著的 Professional Red Hat Enterprise Linux 3(Wrox 出版社,2004 年)。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.