IT貓撲網(wǎng):您身邊最放心的安全下載站! 最新更新|軟件分類|軟件專題|手機版|論壇轉(zhuǎn)貼|軟件發(fā)布

您當前所在位置: 首頁網(wǎng)絡編程PHP編程 → 學習動態(tài)網(wǎng)頁制作PHP技術的正則表達式

學習動態(tài)網(wǎng)頁制作PHP技術的正則表達式

時間:2015-06-28 00:00:00 來源:IT貓撲網(wǎng) 作者:網(wǎng)管聯(lián)盟 我要評論(0)

正則表達式難于書寫、難于閱讀、難于維護,經(jīng)常錯誤匹配意料不到的文本或者錯過了有效的文本,這些問題都是由正則表達式的表現(xiàn)和能力引起的。每個元字符(metacharacter)的能力和細微差別組合在一起,使得代碼不借助于智力技巧就無法解釋。

許多包含一定特性的工具使閱讀和編寫正則表達式變得容易了,但是它們又很不符合習慣。對于很多程序員來說,書寫正則表達式就是一種魔法藝術。他們堅持自己所知道的特征并持有絕對樂觀的態(tài)度。如果你愿意采用本文所探討的五個習慣,你將可以讓你設計的正則表達式經(jīng)受的住反復試驗。

本文將使用Perl、PHPPython語言作為代碼示例,但是本文的建議幾乎適用于任何替換表達式(regex)的執(zhí)行。

一、使用空格和注釋

對于大部分程序員來說,在一個正則表達式環(huán)境里使用空格和縮進排列都不成問題,如果他們沒有這么做一定會被同行甚至外行人士看笑話。幾乎每個人都知道把代碼擠在一行會難于閱讀、書寫和維護。對于正則表達式又有什么不同呢?

大部分替換表達式工具都具有擴展的空格特性,這允許程序員把他們的正則表達式擴展為多行,并在每一行結(jié)尾加上注釋。為什么只有少部分程序員利用這個特性呢?Perl 6的正則表達式默認就是擴展空格的模式。不要再讓語言替你默認擴展空格了,自己主動利用吧。

記住擴展空格的竅門之一就是讓正則表達式引擎忽略擴展空格。這樣如果你需要匹配空格,你就不得不明確說明。

在Perl語言里面,在正則表達式的結(jié)尾加上x,這樣"m/foo|bar/"變?yōu)槿缦滦问剑?/p>

m/

foo

|

bar

/x

在PHP語言里面,在正則表達式的結(jié)尾加上x,這樣""/foo|bar/""變?yōu)槿缦滦问剑?/p>

"/

foo

|

bar

/x"

在Python語言里面,傳遞模式修飾參數(shù)"re.VERBOSE"得到編譯函數(shù)如下:

pattern = r'''

foo

|

bar

'''

regex = re.compile(pattern, re.VERBOSE)

處理更加復雜的正則表達式時,空格和注釋就更能體現(xiàn)出其重要性。假設下面的正則表達式用于匹配美國的電話號碼:

\(?\d{3}\)? ?\d{3}[-.]\d{4}

這個正則表達式匹配電話號碼如"(314)555-4000"的形式,你認為這個正則表達式是否匹配"314-555-4000"或者"555- 4000"呢?答案是兩種都不匹配。寫上這么一行代碼隱蔽了缺點和設計結(jié)果本身,電話區(qū)號是需要的,但是正則表達式在區(qū)號和前綴之間缺少一個分隔符號的說明。

把這一行代碼分成幾行并加上注釋將把缺點暴露無疑,修改起來顯然更容易一些。

在Perl語言里面應該是如下形式:

/

\(? # 可選圓括號

\d{3} # 必須的電話區(qū)號

\)? # 可選圓括號

[-\s.]? # 分隔符號可以是破折號、空格或者句點

\d{3} # 三位數(shù)前綴

[-.] # 另一個分隔符號

\d{4} # 四位數(shù)電話號碼

/x

改寫過的正則表達式現(xiàn)在在電話區(qū)號后有一個可選擇的分隔符號,這樣它應該是匹配"314-555-4000"的,然而電話區(qū)號還是必須的。另一個程序員如果需要把電話區(qū)號變?yōu)榭蛇x項則可以迅速看出它現(xiàn)在不是可選的,一個小小的改動就可以解決這個問題。

二、書寫測試

一共有三個層次的測試,每一層為你的代碼加上一層可靠性。首先,你需要認真想想你需要匹配什么代碼以及你是否能夠處理錯誤匹配。其次,你需要利用數(shù)據(jù)實例來測試正則表達式。最后,你需要正式通過一個測試小組的測試。

決定匹配什么其實就是在匹配錯誤結(jié)果和錯過正確結(jié)果之間尋求一個平衡點。如果你的正則表達式過于嚴格,它將會錯過一些正確匹配;如果它過于寬松,它將會產(chǎn)生一個錯誤匹配。一旦某個正則表達式發(fā)放到實際代碼當中,你可能不會兩者都注意到??紤]一下上面電話號碼的例子,它將會匹配"800-555-4000 = -5355"。錯誤的匹配其實很難發(fā)現(xiàn),所以提前規(guī)劃做好測試是很重要的。

還是使用電話號碼的例子,如果你在Web表單里面確認一個電話號碼,你可能只要滿足于任何格式的十位數(shù)字。但是,如果你想從大量文本里面分離電話號碼,你可能需要很認證的排除不符合要求的錯誤匹配。

在考慮你想匹配的數(shù)據(jù)的時候,寫下一些案例情況。針對案例情況寫下一些代碼來測試你的正則表達式。任何復雜的正則表達式都最好寫個小程序測試一下,可以采用下面的具體形式。

在Perl語言里面:

#!/usr/bin/perl

my @tests = ( "314-555-4000",

"800-555-4400",

"(314)555-4000",

"314.555.4000",

"555-4000",

"aasdklfjklas",

"1234-123-12345"

);

foreach my $test (@tests) {

if ( $test =~ m/

\(? # 可選圓括號

\d{3} # 必須的電話區(qū)號

\)? # 可選圓括號

[-\s.]? # 分隔符號可以是破折號、空格或者句點

\d{3} # 三位數(shù)前綴

[-\s.] # 另一個分隔符號

\d{4} # 四位數(shù)電話號碼

/x ) {

print "Matched on $test\n";

}

else {

print "Failed match on $test\n";

}

}

在PHP語言里面:

$tests = array( "314-555-4000",

"800-555-4400",

"(314)555-4000",

"314.555.4000",

"555-4000",

"aasdklfjklas",

"1234-123-12345"

);

$regex = "/

\(? # 可選圓括號

\d{3} # 必須的電話區(qū)號

\)? # 可選圓括號

[-\s.]? # 分隔符號可以是破折號、空格或者句點

\d{3} # 三位數(shù)前綴

[-\s.] # 另一個分隔符號

\d{4} # 四位數(shù)電話號碼

/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-555-4000",

"800-555-4400",

"(314)555-4000",

"314.555.4000",

"555-4000",

"aasdklfjklas",

"1234-123-12345"

]

pattern = r'''

\(? # 可選圓括號

\d{3} # 必須的電話區(qū)號

\)? # 可選圓括號

[-\s.]? # 分隔符號可以是破折號、空格或者句點

\d{3} # 三位數(shù)前綴

[-\s.] # 另一個分隔符號

\d{4} # 四位數(shù)電話號碼

'''

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"

運行測試代碼將會發(fā)現(xiàn)另一個問題:它匹配"1234-123-12345"。

理論上,你需要整合整個程序所有的測試到一個測試小組里面。即使你現(xiàn)在還沒有測試小組,你的正則表達式測試也會是一個小組的良好基礎,現(xiàn)在正是開始創(chuàng)建的好機會。即使現(xiàn)在還不是創(chuàng)建的合適時間,你也應該在每次修改以后運行測試一下正則表達式。這里花費一小段時間將會減少你很多麻煩事。

三、為交替操作分組

交替操作符號(|)的優(yōu)先級很低,這意味著它經(jīng)常交替超過程序員所設計的那樣。比如,從文本里面抽取Email地址的正則表達式可能如下:

^CC:|To:(.*)

上面的嘗試是不正確的,但是這個bug往往不被注意。上面代碼的意圖是找到"CC:"或者"To:"開始的文本,然后在這一行的后面部分提取Email地址。

不幸的是,如果某一行中間出現(xiàn)"To:",那么這個正則表達式將捕獲不到任何以"CC:"開始的一行,而是抽取幾個隨機的文本。坦白的說,正則表達式匹配 "CC:"開始的一行,但是什么都捕獲不到;或者匹配任何包含"To:"的一行,但是把這行的剩余文本都捕獲了。通常情況下,這個正則表達式會捕獲大量 Email地址,所有沒有人會注意這個bug。

如果要符合實際意圖,那么你應該加入括號說明清楚,正則表達式如下:

(^CC:)|(To:(.*))

如果真正意圖是捕獲以"CC:"或者"To:"開始的文本行的剩余部分,那么正確的正則表達式如下:

^(CC:|To:)(.*)

這是一個普遍的不完全匹配的bug,如果你養(yǎng)成為交替操作分組的習慣,你就會避免這個錯誤。

四、使用寬松數(shù)量詞

很多程序員避免使用寬松數(shù)量詞比如"*?"、"+?"和"??",即使它們會使這個表達式易于書寫和理解。

寬松數(shù)量詞可以盡可能少的匹配文本,這樣有助于完全匹配的成功。如果你寫了"foo(.*?)bar",那么數(shù)量詞將在第一次遇到"bar"時就停止匹配,而不是在最后一次。如果你希望從"foo###bar+++bar"中捕獲"###",這一點就很重要。一個嚴格數(shù)量詞將捕獲"###bar++ +"。

假設你要從HTML文件里面捕獲所有電話號碼,你可能會使用我們上文討論過的電話號碼正則表達式的例子。但是,如果

關鍵詞標簽:PHP

相關閱讀

文章評論
發(fā)表評論

熱門文章 plsql developer怎么連接數(shù)據(jù)庫-plsql developer連接數(shù)據(jù)庫方法 plsql developer怎么連接數(shù)據(jù)庫-plsql developer連接數(shù)據(jù)庫方法 2021年最好用的10款php開發(fā)工具推薦 2021年最好用的10款php開發(fā)工具推薦 php利用淘寶IP庫獲取用戶ip地理位置 php利用淘寶IP庫獲取用戶ip地理位置 在 PHP 中使用命令行工具 在 PHP 中使用命令行工具

相關下載

    人氣排行 詳解ucenter原理及第三方應用程序整合思路、方法 plsql developer怎么連接數(shù)據(jù)庫-plsql developer連接數(shù)據(jù)庫方法 PHP中防止SQL注入攻擊 PHP會話Session的具體使用方法解析 PHP運行出現(xiàn)Notice : Use of undefined constant 的解決辦法 PHP如何清空mySQL數(shù)據(jù)庫 CakePHP程序員必須知道的21條技巧 PHP采集圖片實例(PHP采集)