關(guān)于PCRE的介紹以及實現(xiàn)正則表達(dá)式功能的所有說明,都可以在官方手冊中看到:正則表達(dá)式(兼容 Perl)
一、認(rèn)識PCRE
- PCRE 庫是一個實現(xiàn)了與 perl 5 在語法和語義上略有差異的正則表達(dá)式模式匹配功能的函數(shù)集。
- PCRE 是 PHP 核心擴(kuò)展,所以總是啟用的。默認(rèn)情況下,該擴(kuò)展使用內(nèi)置的 PCRE library。
- 自PHP 5.3.0 起, POSIX 正則表達(dá)式擴(kuò)展被廢棄。所以沒有必要研究 POSIX 正則了。
- PHP 7.0.0 起 PCRE 默認(rèn)支持 JIT(just-in-time)編譯技術(shù),PHP 7.0.12 起可以通過 –without-pcre-jit 禁用 PCRE 的 JIT 功能。PHP 的 Windows 版本已內(nèi)建對此擴(kuò)展的支持。不需要載入額外的擴(kuò)展來使用這些函數(shù)。PHP 5.3.0 的之前版本,可通過 –without-pcre-regex 配置選項禁用此擴(kuò)展。
二、正則語法
1. 詳細(xì)語法參考
- 詳細(xì)的正則語法參考:http://php.net/manual/zh/reference.pcre.pattern.syntax.php
- 正則表達(dá)式全集:http://tool.oschina.net/uploads/apidocs/jquery/regexp.html
2. 詳細(xì)語法參考
字符 | 描述 |
---|---|
\ | 轉(zhuǎn)義符。 |
^ | 匹配輸入字符串的開始位置。 |
$ | 匹配輸入字符串的結(jié)束位置。 |
* | 匹配前面的子表達(dá)式零次或多次。例如,zo*能匹配“z”以及“zoo”。*等價于{0,}。 |
+ | 匹配前面的子表達(dá)式一次或多次。 |
? | 匹配前面的子表達(dá)式零次或一次。 |
{n} | 匹配確定的n次。n是一個非負(fù)整數(shù)。例如,“o{2}”不能匹配“Bob”中的“o”,但是能匹配“food”中的兩個o。 |
{n,} | 至少匹配n次。 |
{n,m} | 最少匹配n次且最多匹配m次。 |
? | 當(dāng)該字符緊跟在任何一個其他限制符(*,+,?,{n},{n,},{n,m})后面時,匹配模式是非貪婪的。非貪婪模式盡可能少的匹配所搜索的字符串,而默認(rèn)的貪婪模式則盡可能多的匹配所搜索的字符串。例如,對于字符串“oooo”,“o+?”將匹配單個“o”,而“o+”將匹配所有“o”。 |
. | 匹配除“\n”之外的任何單個字符。要匹配包括“\n”在內(nèi)的任何字符,請使用像“(.|\n)”的模式。 |
(pattern) | 匹配pattern并獲取這一匹配。 |
x|y | 匹配x或y。例如,“z|food”能匹配“z”或“food”。“(z|f)ood”則匹配“zood”或“food”。 |
[xyz] | 字符集合。匹配所包含的任意一個字符。例如,“[abc]”可以匹配“plain”中的“a”。 |
[^xyz] | 負(fù)值字符集合。匹配未包含的任意字符。例如,“[^abc]”可以匹配“plain”中的“p”。 |
[a-z] | 字符范圍。匹配指定范圍內(nèi)的任意字符。例如,“[a-z]”可以匹配“a”到“z”范圍內(nèi)的任意小寫字母字符。 |
[^a-z] | 負(fù)值字符范圍。匹配任何不在指定范圍內(nèi)的任意字符。例如,“[^a-z]”可以匹配任何不在“a”到“z”范圍內(nèi)的任意字符。 |
\b | 匹配一個單詞邊界,也就是指單詞和空格間的位置。例如,“er\b”可以匹配“never”中的“er”,但不能匹配“verb”中的“er”。 |
\B | 匹配非單詞邊界。“er\B”能匹配“verb”中的“er”,但不能匹配“never”中的“er”。 |
\d | 匹配一個數(shù)字字符。等價于[0-9]。 |
\D | 匹配一個非數(shù)字字符。等價于[^0-9]。 |
\f | 匹配一個換頁符。等價于\x0c和\cL。 |
\n | 匹配一個換行符。等價于\x0a和\cJ。 |
\r | 匹配一個回車符。等價于\x0d和\cM。 |
\s | 匹配任何空白字符,包括空格、制表符、換頁符等等。等價于[ \f\n\r\t\v]。 |
\S | 匹配任何非空白字符。等價于[^ \f\n\r\t\v]。 |
\w | 匹配包括下劃線的任何單詞字符。等價于“[A-Za-z0-9_]”。 |
\W | 匹配任何非單詞字符。等價于“[^A-Za-z0-9_]”。 |
三、PCRE 函數(shù)(本文重點)
1. preg_filter() 執(zhí)行一個正則表達(dá)式搜索和替換
- 語法:mixed preg_filter ( mixed
$pattern
, mixed$replacement
, mixed$subject
[, int$limit
= -1 [, int&$count
]] )
說明:preg_filter()等價于preg_replace() 除了它僅僅返回(可能經(jīng)過轉(zhuǎn)化)與目標(biāo)匹配的結(jié)果。
返回值: 如果subject是一個數(shù)組,返回一個數(shù)組, 其他情況返回一個字符串。如果沒有找到匹配或者發(fā)生了錯誤,當(dāng)subject是數(shù)組 時返回一個空數(shù)組,其他情況返回NULL。
官方示例:
<?php
$subject = array('1', 'a', '2', 'b', '3', 'A', 'B', '4');
$pattern = array('/\d/', '/[a-z]/', '/[1a]/');
$replace = array('A:$0', 'B:$0', 'C:$0');
print_r(preg_filter($pattern, $replace, $subject)); //使用filter
print_r(preg_replace($pattern, $replace, $subject)); //使用replace
/*
返回:
Array
(
[0] => A:C:1
[1] => B:C:a
[2] => A:2
[3] => B:b
[4] => A:3
[7] => A:4
)
Array
(
[0] => A:C:1
[1] => B:C:a
[2] => A:2
[3] => B:b
[4] => A:3
[5] => A
[6] => B
[7] => A:4
)
preg_filter()只返回匹配到的;preg_replace() 返回所有
*/
2. preg_grep() 返回匹配模式的數(shù)組條目
語法:array preg_grep ( string
$pattern
, array$input
[, int$flags
= 0 ] )說明:返回給定數(shù)組input中與模式pattern 匹配的元素組成的數(shù)組.
-
參數(shù):
- pattern,要搜索的模式, 字符串形式.
- input,輸入數(shù)組.
- flags,如果設(shè)置為PREG_GREP_INVERT, 這個函數(shù)返回輸入數(shù)組中與給定模式pattern不匹配的元素組成的數(shù)組
返回值:返回使用input中key做索引的數(shù)組。
-
例子:
<?php $array = array("23.32","22","12.009","23.43.43"); print_r(preg_grep("/^(\d+)?\.\d+$/", $array)); //Array ( [0] => 23.32 [2] => 12.009 ) print_r(preg_grep("/^(\d+)?\.\d+$/", $array, PREG_GREP_INVERT)); //Array ( [1] => 22 [3] => 23.43.43 )
3. preg_last_error() 返回最后一個PCRE正則執(zhí)行產(chǎn)生的錯誤代碼
語法:int preg_last_error ( void )
-
返回值:返回最后一次PCRE正則執(zhí)行的錯誤代碼。
- PREG_NO_ERROR 沒有匹配錯誤
- PREG_INTERNAL_ERROR 有PCRE內(nèi)部錯誤
- PREG_BACKTRACK_LIMIT_ERROR 調(diào)用回溯限制超出
- PREG_RECURSION_LIMIT_ERROR 遞歸限制超出
- PREG_BAD_UTF8_ERROR 異常的utf-8數(shù)據(jù)導(dǎo)致
- PREG_BAD_UTF8_OFFSET_ERROR (自 PHP 5.3.0 起) 偏移量與合法的urf-8代碼不匹配
- PREG_JIT_STACKLIMIT_ERROR (自 PHP 7.0.0 起) 因 JIT 棧空間限制而失敗
具體錯誤代碼的詳情在上面預(yù)定義常量部分。
官方示例:
<?php
$a = preg_match('/(?:\D+|<\d+>)*[!?]/', 'foobar foobar foobar');
if (preg_last_error() == PREG_BACKTRACK_LIMIT_ERROR) {
print 'Backtrack limit was exhausted!';
}
// 輸出:Backtrack limit was exhausted!
4. preg_match() 執(zhí)行匹配正則表達(dá)式
語法:int preg_match ( string
$pattern
, string$subject
[, array &$matches
[, int$flags
= 0 [, int$offset
= 0 ]]] )說明:搜索subject與pattern給定的正則表達(dá)式的一個匹配。
-
參數(shù):
- pattern,要搜索的模式,字符串類型。
- subject,輸入字符串。
- matches,如果提供了參數(shù)matches,它將被填充為搜索結(jié)果。
$matches[0]
將包含完整模式匹配到的文本,$matches[1]
將包含第一個捕獲子組匹配到的文本,以此類推。 - flags,可以被設(shè)置為以下標(biāo)記值:
PREG_OFFSET_CAPTURE,如果傳遞了這個標(biāo)記,對于每一個出現(xiàn)的匹配返回時會附加字符串偏移量(相對于目標(biāo)字符串的)。 注意:這會改變填充到matches參數(shù)的數(shù)組,使其每個元素成為一個由 第0個元素是匹配到的字符串,第1個元素是該匹配字符串 在目標(biāo)字符串subject中的偏移量。 - offset,通常,搜索從目標(biāo)字符串的開始位置開始。可選參數(shù) offset 用于 指定從目標(biāo)字符串的某個位置開始搜索(單位是字節(jié))。
返回值:preg_match()返回 pattern 的匹配次數(shù)。 它的值將是0次(不匹配)或1次,因為preg_match()在第一次匹配后 將會停止搜索。preg_match_all()不同于此,它會一直搜索subject 直到到達(dá)結(jié)尾。 如果發(fā)生錯誤preg_match()返回 FALSE。
例子:
<?php
//從URL中獲取主機(jī)名稱
preg_match('@^(?:http://)?([^/]+)@i', "http://www.php.net/index.html", $matches);
print_r($matches);
// 輸出 Array ( [0] => http://www.php.net [1] => www.php.net )
//獲取主機(jī)名稱的后面兩部分
preg_match('/[^.]+\.[^.]+$/', $matches[1], $matches);
print_r($matches);
// 輸出 Array ( [0] => php.net )
5. preg_match_all() 執(zhí)行一個全局正則表達(dá)式匹配
語法:int preg_match_all ( string
$pattern
, string$subject
[, array &$matches
[, int$flags
= PREG_PATTERN_ORDER [, int$offset
= 0 ]]] )說明: 搜索subject中所有匹配pattern給定正則表達(dá)式的匹配結(jié)果并且將它們以flag指定順序輸出到matches中。在第一個匹配找到后,子序列繼續(xù)從最后一次匹配位置搜索。
-
參數(shù):
- pattern,要搜索的模式,字符串形式。
- subject,輸入字符串。
- matches,多維數(shù)組,作為輸出參數(shù)輸出所有匹配結(jié)果, 數(shù)組排序通過flags指定。
- flags,可以結(jié)合下面標(biāo)記使用(注意不能同時使用PREG_PATTERN_ORDER和PREG_SET_ORDER)
- PREG_PATTERN_ORDER 結(jié)果排序為
matches[1] 保存第一個子組的所有匹配,以此類推。
- PREG_SET_ORDER 結(jié)果排序為
matches[1]是包含第二次匹配到的所有匹配(包含子組)的數(shù)組,以此類推。
- PREG_OFFSET_CAPTURE 如果這個標(biāo)記被傳遞,每個發(fā)現(xiàn)的匹配返回時會增加它相對目標(biāo)字符串的偏移量。 注意這會改變matches中的每一個匹配結(jié)果字符串元素,使其 成為一個第0個元素為匹配結(jié)果字符串,第1個元素為 匹配結(jié)果字符串在subject中的偏移量。
- 如果沒有給定排序標(biāo)記,假定設(shè)置為PREG_PATTERN_ORDER。
- PREG_PATTERN_ORDER 結(jié)果排序為
- offset,通常, 查找時從目標(biāo)字符串的開始位置開始。可選參數(shù)offset用于 從目標(biāo)字符串中指定位置開始搜索(單位是字節(jié))。
返回值:返回完整匹配次數(shù)(可能是0),或者如果發(fā)生錯誤返回FALSE。
例子:
<?php
// \\2是一個后向引用的示例. 這會告訴pcre它必須匹配正則表達(dá)式中第二個圓括號(這里是([\w]+))
// 匹配到的結(jié)果. 這里使用兩個反斜線是因為這里使用了雙引號.
$html = "<b>bold text</b><a href=howdy.html>click me</a>";
preg_match_all("/(<([\w]+)[^>]*>)(.*?)(<\/\\2>)/", $html, $matches, PREG_SET_ORDER);
foreach ($matches as $val) {
echo "matched: " . $val[0] . "\n";
echo "part 1: " . $val[1] . "\n";
echo "part 2: " . $val[2] . "\n";
echo "part 3: " . $val[3] . "\n";
echo "part 4: " . $val[4] . "\n\n";
}
/*以上例程會輸出:
matched: <b>bold text</b>
part 1: <b>
part 2: b
part 3: bold text
part 4: </b>
matched: <a href=howdy.html>click me</a>
part 1: <a href=howdy.html>
part 2: a
part 3: click me
part 4: </a> */
6. preg_quote() 轉(zhuǎn)義正則表達(dá)式字符
語法:string preg_quote ( string
$str
[, string$delimiter
= NULL ] )-
說明: preg_quote()需要參數(shù) str 并向其中每個正則表達(dá)式語法中的字符前增加一個反斜線。 這通常用于你有一些運行時字符串需要作為正則表達(dá)式進(jìn)行匹配的時候。
- 正則表達(dá)式特殊字符有: . \ + * ? [ ^ ] $ ( ) { } = ! < > | : –
- 注意 / 不是正則表達(dá)式特殊字符。
注意:preg_quote() 的應(yīng)用場景不是用于 preg_replace() 的 $replacement 字符串參數(shù)。
-
參數(shù):
- str,輸入字符串
- delimiter,如果指定了可選參數(shù) delimiter,它也會被轉(zhuǎn)義。這通常用于 轉(zhuǎn)義PCRE函數(shù)使用的分隔符。 / 是最常見的分隔符。
返回值:返回轉(zhuǎn)義后的字符串。
-
例子:
<?php $keywords = '$40 for a g3/400'; $keywords1 = preg_quote($keywords); echo $keywords1; // 返回 \$40 for a g3/400 echo "<br>"; $keywords2 = preg_quote($keywords, '/'); echo $keywords2; // 返回 \$40 for a g3\/400 // $是正則表達(dá)式特殊字符, /被當(dāng)參數(shù)傳入也轉(zhuǎn)義
7. preg_replace_callback() 執(zhí)行一個正則表達(dá)式搜索并且使用一個回調(diào)進(jìn)行替換
語法:mixed preg_replace_callback ( mixed
$pattern
, callable$callback
, mixed$subject
[, int$limit
= -1 [, int &$count
]] )說明:這個函數(shù)的行為除了 可以指定一個 callback 替代 replacement 進(jìn)行替換 字符串的計算,其他方面等同于 preg_replace()。
-
參數(shù):
- pattern,要搜索的模式,可以使字符串或一個字符串?dāng)?shù)組。
- callback, 一個回調(diào)函數(shù),在每次需要替換時調(diào)用,調(diào)用時函數(shù)得到的參數(shù)是從subject 中匹配到的結(jié)果。回調(diào)函數(shù)返回真正參與替換的字符串。這是該回調(diào)函數(shù)的簽名:string handler ( array $matches ) 。你可能經(jīng)常會需要callback函數(shù)而 僅用于preg_replace_callback()一個地方的調(diào)用。在這種情況下,你可以 使用匿名函數(shù)來定義一個匿名函數(shù)作 為preg_replace_callback()調(diào)用時的回調(diào)。 這樣做你可以保留所有 調(diào)用信息在同一個位置并且不會因為一個不在任何其他地方使用的回調(diào)函數(shù)名稱而污染函數(shù)名稱空間。
- subject,要搜索替換的目標(biāo)字符串或字符串?dāng)?shù)組。
- limit,對于每個模式用于每個 subject 字符串的最大可替換次數(shù)。 默認(rèn)是-1(無限制)。
- count,如果指定,這個變量將被填充為替換執(zhí)行的次數(shù)。
返回值: 如果subject是一個數(shù)組, preg_replace_callback()返回一個數(shù)組,其他情況返回字符串。 錯誤發(fā)生時返回 NULL。如果查找到了匹配,返回替換后的目標(biāo)字符串(或字符串?dāng)?shù)組), 其他情況subject 將會無變化返回。
官方示例:
<?php
/* 將文本中的年份增加一年 */
$text = "April fools day is 04/01/2002\n";
$text.= "Last christmas was 12/24/2001\n";
// 回調(diào)函數(shù)
function next_year($matches)
{
// 通常: $matches[0]是完成的匹配
// $matches[1]是第一個捕獲子組的匹配
// 以此類推
return $matches[1].($matches[2]+1);
}
$text = preg_replace_callback("|(\d{2}/\d{2}/)(\d{4})|", "next_year", $text);
echo $text;
/*
輸出
April fools day is 04/01/2003
Last christmas was 12/24/2002
*/
8. preg_replace_callback_array() 執(zhí)行一個正則表達(dá)式搜索并且使用多個回調(diào)進(jìn)行替換
語法:mixed preg_replace_callback_array ( array
$patterns_and_callbacks
, mixed$subject
[, int$limit
= -1 [, int &$count
]] )說明:除了回調(diào)函數(shù)是基于每個patterns外,其他方面類似于 preg_replace_callback()。
-
參數(shù):
- patterns_and_callbacks,參數(shù)(keys)對應(yīng)回調(diào)函數(shù)(values)的數(shù)組。
- subject,要搜索替換的目標(biāo)字符串或字符串?dāng)?shù)組。
- limit,對于每個模式用于每個 subject 字符串的最大可替換次數(shù)。 默認(rèn)是-1(無限制)。
- count,如果指定,這個變量將被填充為替換執(zhí)行的次數(shù)。
返回值:
preg_replace_callback_array() 如果參數(shù)是數(shù)組則會返回一個數(shù)組,否則為字符串。出錯時返回 NULL;如果匹配到,會返回一個新的subject-
官方示例:
<?php $subject = 'Aaaaaa Bbb'; preg_replace_callback_array( [ '~[a]+~i' => function ($match) { echo strlen($match[0]), ' matches for "a" found', PHP_EOL; }, '~[b]+~i' => function ($match) { echo strlen($match[0]), ' matches for "b" found', PHP_EOL; } ], $subject ); /* 輸出 6 matches for "a" found 3 matches for "b" found */
9. preg_replace() 執(zhí)行一個正則表達(dá)式的搜索和替換
語法:mixed preg_replace ( mixed
$pattern
, mixed$replacement
, mixed$subject
[, int$limit
= -1 [, int &$count
]] )說明:搜索subject中匹配pattern的部分, 以replacement進(jìn)行替換。
-
參數(shù):
- pattern,要搜索的模式。可以使一個字符串或字符串?dāng)?shù)組。 可以使用一些PCRE修飾符。
- replacement,用于替換的字符串或字符串?dāng)?shù)組。如果這個參數(shù)是一個字符串,并且pattern 是一個數(shù)組,那么所有的模式都使用這個字符串進(jìn)行替換。如果pattern和replacement 都是數(shù)組,每個pattern使用replacement中對應(yīng)的 元素進(jìn)行替換。如果replacement中的元素比pattern中的少, 多出來的pattern使用空字符串進(jìn)行替換。replacement中可以包含后向引用\n 或$n,語法上首選后者。 每個 這樣的引用將被匹配到的第n個捕獲子組捕獲到的文本替換。
- subject,要進(jìn)行搜索和替換的字符串或字符串?dāng)?shù)組。如果subject是一個數(shù)組,搜索和替換回在subject 的每一個元素上進(jìn)行, 并且返回值也會是一個數(shù)組。
- limit,每個模式在每個subject上進(jìn)行替換的最大次數(shù)。默認(rèn)是 -1(無限)。
- count,如果指定,將會被填充為完成的替換次數(shù)。
返回值: 如果subject是一個數(shù)組, preg_replace()返回一個數(shù)組, 其他情況下返回一個字符串。如果匹配被查找到,替換后的subject被返回,其他情況下 返回沒有改變的 subject。如果發(fā)生錯誤,返回 NULL 。
-
例子:
<?php $patterns = array ('/(19|20)(\d{2})-(\d{1,2})-(\d{1,2})/', '/^\s*{(\w+)}\s*=/'); $replace = array ('\3/\4/\1\2', '$\1 ='); echo preg_replace($patterns, $replace, '{startDate} = 1999-5-27'); // 輸出: $startDate = 5/27/1999
10. preg_split() 通過一個正則表達(dá)式分隔字符串
語法:array preg_split ( string
$pattern
, string$subject
[, int$limit
= -1 [, int$flags
= 0 ]] )說明:通過一個正則表達(dá)式分隔給定字符串.
-
參數(shù):
- pattern,用于搜索的模式,字符串形式。
- subject,輸入字符串
- limit,如果指定,將限制分隔得到的子串最多只有l(wèi)imit個,返回的最后一個 子串將包含所有剩余部分。limit值為-1, 0或null時都代表”不限制”, 作為php的標(biāo)準(zhǔn),你可以使用null跳過對flags的設(shè)置。
- flags,可以是任何下面標(biāo)記的組合(以位或運算 | 組合):
- PREG_SPLIT_NO_EMPTY,如果這個標(biāo)記被設(shè)置, preg_split() 將進(jìn)返回分隔后的非空部分。
- PREG_SPLIT_DELIM_CAPTURE,如果這個標(biāo)記設(shè)置了,用于分隔的模式中的括號表達(dá)式將被捕獲并返回。
- PREG_SPLIT_OFFSET_CAPTURE,如果這個標(biāo)記被設(shè)置, 對于每一個出現(xiàn)的匹配返回時將會附加字符串偏移量. 注意:這將會改變返回數(shù)組中的每一個元素, 使其每個元素成為一個由第0 個元素為分隔后的子串,第1個元素為該子串在subject 中的偏移量組成的數(shù)組。
返回值:返回一個使用 pattern 邊界分隔 subject 后得到 的子串組成的數(shù)組, 或者在失敗時返回 FALSE。
-
例子:
<?php //使用逗號或空格(包含" ", \r, \t, \n, \f)分隔短語 $keywords = preg_split ("/[\s,]+/", "hypertext language, programming"); print_r($keywords); // 輸出 // Array ( [0] => hypertext [1] => language [2] => programming )