什么叫正則表達(dá)式
正則表達(dá)式是對(duì)字符串進(jìn)行操作的一種邏輯公式涉波,就是用一些特定的字符組合成一個(gè)規(guī)則字符串该面,稱(chēng)之為正則匹配模式翼悴。
$p = '/apple/';
$str = "apple banna";
if (preg_match($p, $str)) {
echo 'matched';
}
其中字符串'/apple/'就是一個(gè)正則表達(dá)式,他用來(lái)匹配源字符串中是否存在apple字符串谍椅。
PHP中使用PCRE庫(kù)函數(shù)進(jìn)行正則匹配,比如上例中的preg_match用于執(zhí)行一個(gè)正則匹配雏吭,常用來(lái)判斷一類(lèi)字符模式是否存在杖们。
正則表達(dá)式的基本語(yǔ)法
PCRE庫(kù)函數(shù)中,正則匹配模式使用分隔符與元字符組成摘完,分隔符可以是非數(shù)字描焰、非反斜線(xiàn)栅螟、非空格的任意字符。經(jīng)常使用的分隔符是正斜線(xiàn)(/)力图、hash符號(hào)(#) 以及取反符號(hào)(~)吃媒,例如:
/foo bar/
#^[^0-9]$#
~php~
如果模式中包含分隔符,則分隔符需要使用反斜杠(\)進(jìn)行轉(zhuǎn)義赘那。
/http:\/\//
如果模式中包含較多的分割字符募舟,建議更換其他的字符作為分隔符,也可以采用preg_quote進(jìn)行轉(zhuǎn)義拱礁。
$p = 'http://';
$p = '/'.preg_quote($p, '/').'/';
echo $p;
分隔符后面可以使用模式修飾符,模式修飾符包括:i, m, s, x等吴超,例如使用i修飾符可以忽略大小寫(xiě)匹配:
$str = "Http://www.imooc.com/";
if (preg_match('/http/i', $str)) {
echo '匹配成功';
}
元字符與轉(zhuǎn)義
正則表達(dá)式中具有特殊含義的字符稱(chēng)之為元字符鸯乃,常用的元字符有:
\ 一般用于轉(zhuǎn)義字符
^ 斷言目標(biāo)的開(kāi)始位置(或在多行模式下是行首)
$ 斷言目標(biāo)的結(jié)束位置(或在多行模式下是行尾)
. 匹配除換行符外的任何字符(默認(rèn))
[ 開(kāi)始字符類(lèi)定義
] 結(jié)束字符類(lèi)定義
| 開(kāi)始一個(gè)可選分支
( 子組的開(kāi)始標(biāo)記
) 子組的結(jié)束標(biāo)記
? 作為量詞,表示 0 次或 1 次匹配赘娄。位于量詞后面用于改變量詞的貪婪特性遣臼。 (查閱量詞)
* 量詞,0 次或多次匹配
+ 量詞揍堰,1 次或多次匹配
{ 自定義量詞開(kāi)始標(biāo)記
} 自定義量詞結(jié)束標(biāo)記
//下面的\s匹配任意的空白符屏歹,包括空格,制表符蝙眶,換行符。[\s]代表非空白符式塌。[\s]+表示一次或多次匹配非空白符友浸。
$p = '/^我[^\s]+(蘋(píng)果|香蕉)$/';
$str = "我喜歡吃蘋(píng)果";
if (preg_match($p, $str)) {
echo '匹配成功';
}
元字符具有兩種使用場(chǎng)景,一種是可以在任何地方都能使用武学,另一種是只能在方括號(hào)內(nèi)使用伦意,在方括號(hào)內(nèi)使用的有:
\ 轉(zhuǎn)義字符
^ 僅在作為第一個(gè)字符(方括號(hào)內(nèi))時(shí),表明字符類(lèi)取反
- 標(biāo)記字符范圍
其中^在反括號(hào)外面沛鸵,表示斷言目標(biāo)的開(kāi)始位置缆八,但在方括號(hào)內(nèi)部則代表字符類(lèi)取反,方括號(hào)內(nèi)的減號(hào)-可以標(biāo)記字符范圍栏妖,例如0-9表示0到9之間的所有數(shù)字奖恰。
//下面的\w匹配字母或數(shù)字或下劃線(xiàn)宛裕。
$p = '/[\w\.\-]+@[a-z0-9\-]+\.(com|cn)/';
$str = "我的郵箱是Spark.eric@imooc.com";
preg_match($p, $str, $match);
echo $match[0];
貪婪模式與懶惰模式
正則表達(dá)式中每個(gè)元字符匹配一個(gè)字符揩尸,當(dāng)使用+之后將會(huì)變的貪婪屁奏,它將匹配盡可能多的字符,但使用問(wèn)號(hào)?字符時(shí)勇边,它將盡可能少的匹配字符折联,既是懶惰模式。
- 貪婪模式:在可匹配與可不匹配的時(shí)候奕坟,優(yōu)先匹配
//下面的\d表示匹配數(shù)字
$p = '/\d+\-\d+/';
$str = "我的電話(huà)是010-12345678";
preg_match($p, $str, $match);
echo $match[0]; //結(jié)果為:010-12345678
- 懶惰模式:在可匹配與可不匹配的時(shí)候清笨,優(yōu)先不匹配
$p = '/\d?\-\d?/';
$str = "我的電話(huà)是010-12345678";
preg_match($p, $str, $match);
echo $match[0]; //結(jié)果為:0-1
當(dāng)我們確切的知道所匹配的字符長(zhǎng)度的時(shí)候,可以使用{}指定匹配字符數(shù)
$p = '/\d{3}\-\d{8}/';
$str = "我的電話(huà)是010-12345678";
preg_match($p, $str, $match);
echo $match[0]; //結(jié)果為:010-12345678
使用正則表達(dá)式進(jìn)行匹配
使用正則表達(dá)式的目的是為了實(shí)現(xiàn)比字符串處理函數(shù)更加靈活的處理方式,因此跟字符串處理函數(shù)一樣跌帐,其主要用來(lái)判斷子字符串是否存在绊率、字符串替換、分割字符串脸狸、獲取模式子串等藐俺。
PHP使用PCRE庫(kù)函數(shù)來(lái)進(jìn)行正則處理,通過(guò)設(shè)定好模式卿啡,然后調(diào)用相關(guān)的處理函數(shù)來(lái)取得匹配結(jié)果菱父。
preg_match用來(lái)執(zhí)行一個(gè)匹配剑逃,可以簡(jiǎn)單的用來(lái)判斷模式是否匹配成功官辽,或者取得一個(gè)匹配結(jié)果,他的返回值是匹配成功的次數(shù)0或者1萤捆,在匹配到1次以后就會(huì)停止搜索乓梨。
$subject = "abcdef";
$pattern = '/def/';
preg_match($pattern, $subject, $matches);
print_r($matches); //結(jié)果為:Array ( [0] => def )
上面的代碼簡(jiǎn)單的執(zhí)行了一個(gè)匹配扶镀,簡(jiǎn)單的判斷def是否能匹配成功,但是正則表達(dá)式的強(qiáng)大的地方是進(jìn)行模式匹配臭觉,因此更多的時(shí)候蝠筑,會(huì)使用模式:
$subject = "abcdef";
$pattern = '/a(.*?)d/';
preg_match($pattern, $subject, $matches);
print_r($matches); //結(jié)果為:Array ( [0] => abcd [1] => bc )
通過(guò)正則表達(dá)式可以匹配一個(gè)模式,得到更多的有用的數(shù)據(jù)挽封。
查找所有匹配結(jié)果
preg_match只能匹配一次結(jié)果臣镣,但很多時(shí)候我們需要匹配所有的結(jié)果,preg_match_all可以循環(huán)獲取一個(gè)列表的匹配結(jié)果數(shù)組点待。
$p = "|<[^>]+>(.*?)</[^>]+>|i";
$str = "<b>example: </b><div align=left>this is a test</div>";
preg_match_all($p, $str, $matches);
print_r($matches);
可以使用preg_match_all匹配一個(gè)表格中的數(shù)據(jù):
$p = "/<tr><td>(.*?)<\/td>\s*<td>(.*?)<\/td>\s*<\/tr>/i";
$str = "<table> <tr><td>Eric</td><td>25</td></tr> <tr><td>John</td><td>26</td></tr> </table>";
preg_match_all($p, $str, $matches);
print_r($matches);
$matches結(jié)果排序?yàn)?matches[0]保存完整模式的所有匹配, $matches[1] 保存第一個(gè)子組的所有匹配弃舒,以此類(lèi)推聋呢。
正則表達(dá)式的搜索和替換
正則表達(dá)式的搜索與替換在某些方面具有重要用途,比如調(diào)整目標(biāo)字符串的格式削锰,改變目標(biāo)字符串中匹配字符串的順序等喂窟。
例如我們可以簡(jiǎn)單的調(diào)整字符串的日期格式:
$string = 'April 15, 2014';
$pattern = '/(\w+) (\d+), (\d+)/i';
$replacement = '$3, ${1} $2';
echo preg_replace($pattern, $replacement, $string); //結(jié)果為:2014, April 15
其中${1}與$1的寫(xiě)法是等效的央串,表示第一個(gè)匹配的字串碗啄,$2代表第二個(gè)匹配的。
通過(guò)復(fù)雜的模式饲宿,我們可以更加精確的替換目標(biāo)字符串的內(nèi)容胆描。
$patterns = array ('/(19|20)(\d{2})-(\d{1,2})-(\d{1,2})/',
'/^\s*{(\w+)}\s*=/');
$replace = array ('\3/\4/\1\2', '$\1 =');//\3等效于$3,\4等效于$4,依次類(lèi)推
echo preg_replace($patterns, $replace, '{startDate} = 1999-5-27'); //結(jié)果為:$startDate = 5/27/1999
//詳細(xì)解釋下結(jié)果:(19|20)表示取19或者20中任意一個(gè)數(shù)字短绸,(\d{2})表示兩個(gè)數(shù)字醋闭,(\d{1,2})表示1個(gè)或2個(gè)數(shù)字,(\d{1,2})表示1個(gè)或2個(gè)數(shù)字乐埠。^\s{(\w+)\s=}表示以任意空格開(kāi)頭的囚企,并且包含在{}中的字符,并且以任意空格結(jié)尾的,最后有個(gè)=號(hào)的烦衣。
用正則替換來(lái)去掉多余的空格與字符:
$str = 'one two';
$str = preg_replace('/\s+/', ' ', $str);
echo $str; // 結(jié)果改變?yōu)?one two'