正则环视 php,正则表达式基本知识(php)
這里的知識點(diǎn)基本上是《正則指引》的讀書筆記,只是每個(gè)知識點(diǎn)的示例代碼用php來實(shí)現(xiàn)。
1. 字符組
字符組(Character Class)就是一組字符,在正則表達(dá)式中,它表示“在同一個(gè)位置可能出現(xiàn)的各種字符”。
寫法:[ab]、[314]、[#.?]
字符組的基本用法
[...]
preg_match('/[0123456]/', '5'); // => 1
preg_match('/[abc123]/', '5'); // => 0
范圍表示法(range)
[x-y]表示x到y(tǒng)整個(gè)范圍內(nèi)的字符。如,[0123456789]表示為[0-9],[abcdefghijk]表示為[a-k]。
為什么是[0-9],而不是[9-0]?
因?yàn)?表示的范圍一般是根據(jù)字符對應(yīng)的碼值(Code Point)來確定的。典型地有ACSⅡ編碼。在ACSⅡ編碼中,0~9的碼值是48~57,a~z的碼值是97~122,A~Z的碼值是65~90。
preg_match('/[0-9]/', '5'); // => 1
preg_match('/[a-z]/', '5'); // => 0
preg_match('/[0-9a-fA-F]/', '0'); // 16進(jìn)制
字符組簡記法(shorthands)
提供比范圍表示法更簡潔的表示方法,如\d表示[0-9],\w表示[0-9a-zA-z_]。
php中支持的字符組簡記:
\d 所有的數(shù)字,即[0-9]
\D 所有的非數(shù)字,與\d互斥
\w 所有的單詞字符(字符、數(shù)字、下劃線),即[0-9a-zA-Z_]
\W 所有的非單詞字符,與\W互斥
\s 所有的空白字符,包括空格、制表符、回車符、換行符等空白字符
\S 所有的非空白字符,與\s互斥
preg_match('/\d/', '8'); // => 1
preg_match('/\d/', 'a'); // => 0
preg_match('/\d[a-z]/', 'a'); // => 1
preg_match('/\w/', 'a'); // => 1
preg_match('/\w/', '6'); // => 1
preg_match('/\w/', '_'); // => 1
preg_match('/\s/', ' '); // => 1
preg_match('/\s/', "\t"); // => 1
preg_match('/\s/', "\r"); // => 1
元字符與轉(zhuǎn)義
在范圍表示法中,字符組中的橫線-不能匹配橫線字符,而是用來表示范圍,這類字符叫做元字符(meta-character)。元字符除了-還有開方括號[、閉剛括號]、^、$等,它們都有特殊的意義。
當(dāng)元字符想要表示普通字符的含義時(shí)(如-就只想表示橫線字符),就需要轉(zhuǎn)義處理(在元字符前加反斜線字符\)。對于-,有一個(gè)例外情況,就是當(dāng)它緊跟著字符組中的開括號[時(shí),它就表示普通橫線字符,此時(shí)不用轉(zhuǎn)義。
preg_match('/[0\-9]/', "-"); // => 1
preg_match('/[0\-9]/', "8"); // => 0
preg_match('/[0\-9]/', "0"); // => 1
preg_match('/[-09]/', "-"); // => 1
preg_match("/[0\\-9]/", "-"); // => 1
preg_match("/[0\-9]/", "-"); // => 1
仔細(xì)看上面第一個(gè)表達(dá)式和最后兩個(gè)表示式。這里要注意:
在php中,字符串既可以用單引號標(biāo)注也可以用雙引號標(biāo)注。兩者的主要區(qū)別在于,雙引號字符串可以插值,二單引號字符串不能;另外,雙引號字符串會(huì)處理字符串轉(zhuǎn)義,二單引號字符串不會(huì)
正則表達(dá)式是以字符串的方式提供的。在php中,雙引號字符串本身也有關(guān)于轉(zhuǎn)義的規(guī)定(如"\\"、'\r'、"\t"等),因此"0\\-9"與'0\-9'是等價(jià)的。
那么最后一個(gè)表達(dá)式為什么也可以匹配呢?這是因?yàn)?#xff0c;盡管php的正則表達(dá)式用字符串文字給出,但它與常見的字符串不完全一樣——如果某個(gè)轉(zhuǎn)義序列可以有字符串識別,則對其進(jìn)行轉(zhuǎn)義處理;否則,將整個(gè)轉(zhuǎn)義序列“原封不動(dòng)”地保存下來。
因此,在正則表達(dá)式中轉(zhuǎn)義要小心,在php中,使用單引號字符串來構(gòu)建正則表達(dá)式會(huì)比雙引號字符串更簡單明了。
排除型字符組(Negated Character Class)
在方括號[…]中列出希望匹配的所有字符叫做“普通字符組”。在開方括號[之后緊跟一個(gè)脫字符^,寫作[^…],表示“在當(dāng)前位置,匹配一個(gè)沒有列出的字符”。例如,[^0-9]匹配非數(shù)字字符。
preg_match('/[^0-9][0-9]/', "A8"); // => 1
排除型字符組中的緊跟著開方括號[的脫字符^也是元字符,如果要匹配尖括號字符,需要進(jìn)行轉(zhuǎn)義處理。但是,不緊跟著開方括號[的^就是普通字符,不需要轉(zhuǎn)義。
preg_match('/[^0-9]/', '0'); // => 0
preg_match('/[\^0-9]/', '0'); // => 1
preg_match('/[\^0-9]/', '^'); // => 1
preg_match('/[0-9^]/', '^'); // => 1
POSIX字符組
之前介紹的字符組,都屬于Perl衍生出來的正則表達(dá)式流派(Flavor),這個(gè)流派叫做PCRE(Per Compatible Regular Expression)。正則表達(dá)式還有其他流派,比如POSIX(Portable Operating System Interface for unix),它是一系列規(guī)范,定義了UNIX操作系統(tǒng)應(yīng)當(dāng)支持的功能,其中也包括了正則表達(dá)式的規(guī)范。
常見的[a-z]形式的字符組,在POSIX規(guī)范中仍然獲得支持,稱作POSIX方括號表達(dá)式。POSIX方括號表達(dá)式中的\不是用來轉(zhuǎn)義的,如[\d]就只能匹配\和d兩個(gè)字符。這里涉及到]、-這兩個(gè)特殊字符,在POSIX規(guī)范中,緊接在開方括號[之后的]才表示閉方括號字符,緊挨在閉方括號]之前的-才表示橫線字符。
對于PCRE規(guī)范中的\d、\w、\s等字符組簡記法,POSIX中有類似的東西,叫做POSIX字符組。在ASCⅡ語言環(huán)境(locale)中,常見的POSIX字符組及其含義如下:
POSIX字符組
說明
ACSⅡ字符組
等價(jià)的PCRE簡記法
[:alnum:]
字母和數(shù)字
[0-9a-zA-Z]
[:alpha:]
字母
[a-zA-Z]
[:ASCⅡ]
ASCⅡ字符
[\x00-\x7F]
[:blank:]
空格字符和制表字符
[ \t]
[:cntrl:]
控制字符
[\x00-\x1F\x7F]
[:digit:]
數(shù)字字符
[0-9]
\d
[:graph:]
空白字符之外的字符
[\x21-\x7E]
[:lower:]
小寫字母字符
[a-z]
[:print:]
類似[:graph:],但包括空白字符
[\x20-\x7E]
[:punct:]
標(biāo)點(diǎn)符號
[][!"#$%&'()*+,./:;<=>?@\^_`{\
}~-]
[:space:]
空白字符
[ \t\r\n\v\f]
\s
[:upper:]
大寫字母
[A-Z]
[:word:]
字母字符
[A-Za-z0-9_]
\w
[:xdigit:]
十六進(jìn)制字符
[A-Fa-f0-9]
php中有專門處理POSIX正則的函數(shù),但從5.3.0開始已經(jīng)廢棄了。這里只是了解一下相關(guān)知識。
2. 量詞
這里首先介紹一下^和$兩個(gè)特殊字符,在上一章的元字符與轉(zhuǎn)義一節(jié)提到過這兩個(gè)特殊字符。
^放在正則表達(dá)式的開頭,表示“定位到字符串的起始位置”;$用在正則表達(dá)式的末尾,表示“定位到字符串的結(jié)束位置”。
preg_match('/\w\d/', '1a2b'); // => 1
preg_match('/^\w\d/', '1a2b'); // => 0 必須以字母開頭
preg_match('/\w\d$/', '1a2b'); // => 0 必須以數(shù)字結(jié)尾
preg_match('/^\w\d/', 'a2b'); // => 1
preg_match('/\w\d$/', '1a2'); // => 1
preg_match('/^\w\d$/', '1a2'); // => 0 開頭必須是字母,結(jié)尾必須是數(shù)字
preg_match('/^\w\d$/', 'a2'); // => 1
量詞的一般形式
如果要匹配一個(gè)郵政編碼(6位數(shù)字),目前能寫出來的正則表達(dá)式是^\d\d\d\d\d\d$:
preg_match('/^\d\d\d\d\d\d$/', '100010'); // => 1
preg_match('/^\d\d\d\d\d\d$/', '10001035'); // => 0
preg_match('/^\d\d\d\d\d\d$/', '10a010'); // => 0
\d重復(fù)6次的寫法很不科學(xué),正則表達(dá)式肯定會(huì)有更方便的寫法,也就是量詞(quantifier)。量詞的通用形式是{m,n}(注意,,后面不能有空格),它限定之前的元素能夠出現(xiàn)的次數(shù),m是下限,n是上限。其他常見的量詞形式有:
量詞
說明
{n}
之前的元素必須出現(xiàn)n次
{m,n}
之前的元素最少出現(xiàn)m次,最多出現(xiàn)n次
{m,}
之前的元素最少出現(xiàn)m次,出現(xiàn)次數(shù)無上限
{0,n}
之前的元素可以不出現(xiàn),也可以出現(xiàn),最多出現(xiàn)n次
preg_match('/^\d{6}$/', '100010'); // => 1
preg_match('/^\d{4,6}$/', '123'); // => 0
preg_match('/^\d{4,6}$/', '1234'); // => 1
preg_match('/^\d{4,6}$/', '123456'); // => 1
preg_match('/^\d{4,6}$/', '1234567'); // => 0
常用量詞
正則表達(dá)式還有三個(gè)常用的量詞,分別是+、?、*:
常用量詞
{m,n}等價(jià)形式
說明
*
{0,}
可能出現(xiàn),也可能不出現(xiàn),出現(xiàn)次數(shù)沒有上限
+
{1,}
至少出現(xiàn)1次,出現(xiàn)次數(shù)沒有上限
?
{0,1}
出現(xiàn)0次或1次
這三種量詞在實(shí)際中使用的非常多。
例如,匹配url的時(shí)候,有可能是http,也有可能是https,這個(gè)時(shí)候用?就很方便:
preg_match('/^https?:\/\/www\.baidu\.com/', 'http://www.baidu.com'); // => 1
preg_match('/^https?:\/\/www\.baidu\.com/', 'https://www.baidu.com'); // => 1
在匹配html的tag(如
、、等)的時(shí)候,在中間會(huì)有字符,但是字符長度不確定。這種情況下就需要使用+了:preg_match('/^]+>$/', ''); // => 1
preg_match('/^]+>$/', ''); // => 1
preg_match('/^]+>$/', '<>'); // => 0
如果說匹配一個(gè)雙引號字符串,在雙引號內(nèi),既可以出現(xiàn)字符也可以不出現(xiàn)字符。這種情況下就應(yīng)該使用量詞*。
preg_match('/^\"[^\"]*\"$/', '""'); // => 1
preg_match('/^\"[^\"]*\"$/', '"abcd"'); // => 1
點(diǎn)號
點(diǎn)號.是與量詞搭配比較多得一個(gè)字符。一般情況下,點(diǎn)號.可以匹配除了換行符\n以外的任意字符。
preg_match('/^.$/', 'z'); // => 1
preg_match('/^.$/', '8'); // => 1
preg_match('/^.$/', "\n"); // => 0
如果要使.能匹配的字符包含換行符\n,可以使用自制通配符\s\S或\w\W、\d\D。
preg_match('/^[\s\S]$/', "\n"); // => 1
使.能匹配的字符包含換行符\n的另外一種方法是指定正則匹配時(shí)使用單行模式。在php中,可以使用模式修飾符和預(yù)定義常量兩種方法來指定單行模式。關(guān)于正則匹配的模式,后面會(huì)詳細(xì)介紹。
preg_match('/(?s)^.$/', "\n"); // => 1 模式修飾符
preg_match('/^.$/s', "\n"); // => 1 預(yù)定義常量
匹配優(yōu)先量詞、忽略優(yōu)先量詞
很多語言中,都可以使用/*...*/來注釋代碼,如果是一個(gè)支持語法高亮的文本編輯器就要能夠提取/*...*/注釋塊。很easy的,我們可以寫出如下正則表達(dá)式:
$str = '/*this is a comment*/ /*this is another comment*/';
preg_match('/\/\*.*\*\//', $str, $arr);
echo $arr[0];
/*this is a comment*/ /*this is another comment*/
可以看到,這個(gè)正則表達(dá)式出了點(diǎn)小問題,它把兩個(gè)注釋塊匹配出來了,如果兩個(gè)注釋塊中間有代碼,那么代碼也會(huì)匹配出來。
這是因?yàn)?#xff0c;我們介紹的*、+、?都是匹配優(yōu)先量詞(greedy quantifier,也稱貪婪量詞)。匹配優(yōu)先量詞是指在拿不準(zhǔn)是否要匹配的時(shí)候,優(yōu)先嘗試匹配。因此,$str中間的*/ /*都被.*匹配了。
正則表達(dá)式中利用忽略優(yōu)先量詞來解決上述問題。與*、+、?對應(yīng)的忽略優(yōu)先量詞的形式是*?、+?、??。忽略優(yōu)先量詞在不確定是否要匹配時(shí)選擇“不匹配”的狀態(tài)。還是以提取注釋塊的代碼為例:
preg_match('/\/\*.*?\*\//', $str, $arr);
echo $arr[0];
/*this is a comment*/
這樣就達(dá)到了提取注釋塊的效果。
匹配優(yōu)先量詞
忽略優(yōu)先量詞
限定次數(shù)
*
*?
可能出現(xiàn),可能不出現(xiàn),出現(xiàn)次數(shù)沒有上限
+
+?
至少出現(xiàn)1次,沒有上限
?
??
出現(xiàn)0次或1次
{m,n}
{m,n}?
出現(xiàn)次數(shù)大于等于m,小于等于n
{m,}
{m,}?
至少出現(xiàn)m次,沒有上限
{0,n}
{0,n}?
出現(xiàn)0次-n次
php中有指定非貪婪匹配模式的模式修飾符和預(yù)定義常量,與忽略優(yōu)先量詞是一樣的效果:
// 默認(rèn)貪婪匹配
preg_match('/\/\*.*\*\//', $str, $arr); // => /*this is a comment*/ /*this is another comment*/
// 預(yù)定義常量 指定非貪婪匹配
preg_match('/\/\*.*\*\//U', $str, $arr); // => /*this is a comment*/
// 模式修飾符 指定非貪婪匹配
preg_match('/(?U)\/\*.*\*\//', $str, $arr); // => /*this is a comment*/
// 同時(shí)使用 忽略優(yōu)先量詞 和 預(yù)定義常量
preg_match('/\/\*.*?\*\//U', $str, $arr); // => /*this is a comment*/ /*this is another comment*/
// 同時(shí)使用 忽略優(yōu)先量詞 和 模式修飾符
preg_match('/(?U)\/\*.*?\*\//', $str, $arr); // => /*this is a comment*/ /*this is another comment*/
量詞的轉(zhuǎn)義
*、+、?的轉(zhuǎn)義比較簡單,就是\*、\+、\?。主要是{m,n}形式的轉(zhuǎn)義需要注意。
量詞
轉(zhuǎn)義
量詞
轉(zhuǎn)義
量詞
轉(zhuǎn)義
{n}
\\{n}
*
\*
*?
\*\?
{m,n}
\\{m,n}
+
\\+
+?
\\+\?
{m,}
\\{m,}
?
\?
??
\?\?
{0,n}
\\{0,n}
3.括號
分組
上一章介紹了量詞,上一章的例子中量詞都只能控制它前面的字符或字符組。那么量詞能否控制連續(xù)的字符或字符組呢,如控制一個(gè)單詞hello出現(xiàn)或者不出現(xiàn)。這就要用到正則表達(dá)式的分組功能(子表達(dá)式),使用圓括號(...)實(shí)現(xiàn)分組(子表達(dá)式)。
// 量詞限定前面一個(gè)字符
preg_match('/^hello?, world$/', 'hello, world'); // => 1
preg_match('/^hello?, world$/', 'hell, world'); // => 1
preg_match('/^hello?, world$/', ', world'); // => 0
// 量詞限定一個(gè)單詞
preg_match('/^(hello)?, world$/', 'hello, world'); // => 1
preg_match('/^(hello)?, world$/', 'hell, world'); // => 0
preg_match('/^(hello)?, world$/', ', world'); // => 1
多選結(jié)構(gòu)
多選結(jié)構(gòu)(alternative)的形式是(...|...),在括號內(nèi)以豎線|分開多個(gè)子表達(dá)式,這些子表達(dá)式也叫多選分支(option)。
例如,匹配常見的11位手機(jī)號
// 匹配常見11位手機(jī)號
preg_match('/(13[0-9]|15[0-356]|18[025-9])\d{8}/', '18521510001', $arr); // => 1
引用分組
正則表達(dá)式會(huì)保存每個(gè)(...)分組匹配的文本,這種功能叫捕獲分組(capturing group)。在需要直接使用子表達(dá)式的時(shí)候非常有用
例如,提取標(biāo)簽中的地址和描述文本
// 提取標(biāo)簽中的地址和描述文本
preg_match('/(.*?)/', 'visit github', $arr);
print_r($arr);
/*
Array
(
[0] => github
[1] => github.com
[2] => visit github
)
*/
正則表達(dá)式替換時(shí)也支持捕獲分組。php中支持\num和$num的形式替換,但是num不能大于10;另一種形式${num}可以大于10。
例如,日期的替換
// 正則表達(dá)式替換
preg_replace('/(\d{4})-(\d{2})-(\d{2})/', '$1年$2月$3日', '2015-08-25'); // => 2015年08月25日
preg_replace('/(\d{4})-(\d{2})-(\d{2})/', '\1年\2月\3日', '2015-08-25'); // => 2015年08月25日
反向引用
在正則表達(dá)式內(nèi)部引用之前的捕獲分組匹配的文本叫反向引用(back-reference)。實(shí)測php支持\num形式的反向引用,不支持$num形式的反向引用
例如,利用反向引用匹配id相同的不同標(biāo)簽
// 匹配id為main的標(biāo)簽
preg_match('/.*?/', '
hello, world', $arr); // => 1print_r($arr);
/*
Array
(
[0] =>
hello, world[1] => div
)
*/
// 匹配id為main的標(biāo)簽
preg_match('/.*?/', '
Hello, World
', $arr); // => 1print_r($arr);
/*
Array
(
[0] =>
Hello, World
[1] => p
)
*/
命名分組
數(shù)字編號的分組有時(shí)候不夠直觀,因此有些語言和工具的正則表達(dá)式提供了命名分組(named grouping)。
正則字符中(?P)來命名,(?P=name)來使用。preg_replace替換時(shí)不支持
// 捕獲命名分組
preg_match('/[^\'"\s]*)">(?P.*?)/', '', $arr);
print_r($arr);
/*
Array
(
[0] => visit github
[link] => github.com
[1] => github.com
[description] => visit github
[2] => visit github
)
*/
// 反向引用命名分組
preg_match('/[\w]+)\s+id="main">.*?/', '
hello, world', $arr);print_r($arr);
/*
Array
(
[0] =>
hello, world[tag] => div
[1] => div
)
*/
非捕獲分組
正則表達(dá)式默認(rèn)會(huì)保存每個(gè)(...)匹配的文本,前面利用這個(gè)特性可以實(shí)現(xiàn)一些有用的功能。但是,有時(shí)候正則表達(dá)式比較復(fù)雜,(...)會(huì)出現(xiàn)的比較多,而此時(shí)僅僅是想實(shí)現(xiàn)分組或者多選的功能,而不需要捕獲分組;同時(shí),大量不需要的捕獲分組可能會(huì)影響性能。
為了解決這種問題,正則表達(dá)式提供了非捕獲分組(non-capturing group),它的形式是(?:...)。
// 捕獲分組
preg_match('/(13[0-9]|15[0-356]|18[025-9])\d{8}/', '18521510001', $arr); // => 1
print_r($arr);
/*
Array
(
[0] => 18521510001
[1] => 185
)
*/
// 非捕獲分組
echo preg_match('/(?:13[0-9]|15[0-356]|18[025-9])\d{8}/', '18521510001', $arr); // => 1
print_r($arr);
/*
Array
(
[0] => 18521510001
)
*/
4.斷言
正則表達(dá)式中的有些結(jié)構(gòu)不匹配真正的文本,只負(fù)責(zé)判斷在某個(gè)位置左/右側(cè)的文本是否符合要求,這種結(jié)構(gòu)稱為斷言(assertion)。常見的斷言有三類:單詞邊界、行起始/結(jié)束位置、環(huán)視。
單詞邊界
單詞邊界(word boundary),記為\b。它匹配的是單詞邊界(一邊是單詞字符,另一邊不是單詞字符)的位置,而不是字符。
// 單詞邊界
preg_match('/\b\w+\b/', 'word', $arr); // => 1
print_r($arr);
/*
Array
(
[0] => word
)
*/
// 匹配所有單詞邊界
preg_match_all('/\b\w+\b/', 'hello, world', $arr); // => 2
print_r($arr);
/*
Array
(
[0] => Array
(
[0] => hello
[1] => world
)
)
*/
這類匹配位置而不匹配字符的元素叫做錨點(diǎn)(anchor),下一節(jié)要介紹的^、$等也是錨點(diǎn)。
行起始/結(jié)束位置
^:字符串的開始位置
$:字符串的結(jié)束位置
$str = 'first line
second line
last line';
// 字符串起始位置
preg_match_all('/^\w+\b/', $str, $arr); // => 1
print_r($arr);
/*
Array
(
[0] => Array
(
[0] => first
)
)
*/
// 字符串結(jié)束位置
preg_match_all('/\b\w+$/', $str, $arr); // => 1
print_r($arr);
/*
Array
(
[0] => Array
(
[0] => line
)
)
*/
如果指定了多行模式(Multiline Mode),^、$分別可以匹配行起始位置、行結(jié)束位置。關(guān)于模式,將在下一章詳細(xì)介紹。指定多行模式的方式是使用模式修飾符(?m):在正則表達(dá)式之前加上(?m);或者是預(yù)定義常量的方式:/.../m 。
// 多行模式 行起始位置
// preg_match_all('/^\w+\b/m', $str, $arr); 是一樣的效果
preg_match_all('/(?m)^\w+\b/', $str, $arr); // => 3
print_r($arr);
/*
Array
(
[0] => Array
(
[0] => first
[1] => second
[2] => last
)
)
*/
//多行模式 行結(jié)束位置
// preg_match_all('/\b\w+$/m', $str, $arr); 是一樣的效果
preg_match_all('/(?m)\b\w+$/', $str, $arr); // => 3
print_r($arr);
/*
Array
(
[0] => Array
(
[0] => line
[1] => line
[2] => line
)
)
*/
\A不論是普通模式還是多行模式,都匹配字符串起始位置
\Z、\z不論是普通模式還是多行模式,都匹配字符串結(jié)束位置
\Z與\z的區(qū)別在于最后字符串的末尾是行終止符的時(shí)候,\Z匹配行終止符之前的位置,\z則不管行終止符,只匹配“整個(gè)字符串的結(jié)束位置”。
這里用行終止符,而不用換行符的原因是不同操作系統(tǒng)的行終止符不同(windows\r\n,linux\n,mac\n)。
// \A 始終匹配字符串起始位置
preg_match_all('/\A\w+\b/', $str, $arr); // => 1
print_r($arr);
/*
Array
(
[0] => Array
(
[0] => first
)
)
*/
preg_match_all('/(?m)\A\w+\b/', $str, $arr); // => 1
print_r($arr);
/*
Array
(
[0] => Array
(
[0] => first
)
)
*/
// \Z始終匹配行結(jié)束位置
preg_match_all('/\b\w+\Z/', $str, $arr); // => 1
print_r($arr);
/*
Array
(
[0] => Array
(
[0] => line
)
)
*/
preg_match_all('/(?m)\b\w+\Z/', $str, $arr); // => 1
print_r($arr);
/*
Array
(
[0] => Array
(
[0] => line
)
)
*/
// \Z \z的區(qū)別
$str = 'first line
second line
last line
';
preg_match_all('/(?m)\b\w+\z/', $str, $arr); // => 0
print_r($arr);
/*
Array
(
[0] => Array
(
)
)
*/
preg_match_all('/(?m)\b\w+\Z/', $str, $arr); // => 1
print_r($arr);
/*
Array
(
[0] => Array
(
[0] => line
)
)
*/
環(huán)視
環(huán)視(look-around)用來“停在原地,四處張望”,它本身也不匹配任何字符,用來限定它旁邊的文本滿足某種條件。
名字
記法
含義
肯定順序環(huán)視
(?=...)
向右看看,右邊出現(xiàn)了環(huán)視中的內(nèi)容才匹配
否定順序環(huán)視
(?!...)
向右看看,右邊不出現(xiàn)環(huán)視中的內(nèi)容才匹配
肯定逆序環(huán)視
(?<=...)
向左看看,左邊出現(xiàn)了環(huán)視中的內(nèi)容才匹配
否定逆序環(huán)視
(?
向左看看,左邊不出現(xiàn)環(huán)視中的內(nèi)容才匹配
例如,要匹配html標(biāo)簽中的開標(biāo)簽(、
、等),而不能匹配閉標(biāo)簽(、、等)和自閉和標(biāo)簽(等),同時(shí),也不能匹配一個(gè)空的標(biāo)簽<>。
直接使用將/字符排除是不對的,因?yàn)橛行?biāo)簽的屬性中可能會(huì)含有/字符。例如。這里只是在開尖括號之前的第一個(gè)字符不能為/。
然而]*[^\/]>也是不行的,因?yàn)樵谥g會(huì)至少匹配兩個(gè)字符,像這樣的標(biāo)簽是無法匹配到的。這里就要用到環(huán)視了。
上面的正則表達(dá)式中有兩個(gè)環(huán)視結(jié)構(gòu),一個(gè)在開尖括號之前,表示在閉尖括號>之前向左看看,左邊挨著的字符不能為/。
上面的正則表達(dá)式已經(jīng)解決了匹配html中開標(biāo)簽的主要問題,只是其中的.*?還需要優(yōu)化一下。需要解決的問題是:
有可能會(huì)有單引號'或雙引號",它們都得成對出現(xiàn)
單引號對或雙引號對之內(nèi)可以有>字符,但是它們的外面不能有>字符
利用正則表達(dá)式的選擇結(jié)構(gòu),可以寫出下面的表達(dá)式,用于完善上面的問題。
])+(?
5.匹配模式
前面的內(nèi)容中已經(jīng)出現(xiàn)介過了單行模式、多行模式、非貪婪模式。匹配模式是指匹配時(shí)使用的規(guī)則。常用的匹配模式還有不區(qū)分大小寫模式、注釋模式。
在開始介紹具體的模式之前,先介紹php中模式的兩種具體實(shí)現(xiàn)/.../{modifier}和...(?{modifier})...:
模式修飾符
/.../{modifier}
...(?{modifier})...
示例
/
.*/s(?s).*名稱(php手冊)
模式修飾符
模式內(nèi)修飾符
名稱(《正則指引》)
預(yù)定義常量
模式修飾符
作用范圍
整個(gè)正則表達(dá)式
不在分組(子表達(dá)式)中時(shí),對它后面的全部正則表達(dá)式起作用;如果在分組(子表達(dá)式)中,則對它分組中的剩余部分起作用。在沒有分組,且放在整個(gè)正則表達(dá)式最前面的時(shí)候相當(dāng)于/.../{modifier}
支持程度
支持所有模式修飾符
支持部分模式修飾符
其他編程語言
可能不支持
一般都支持
不區(qū)分大小寫模式
在html中是不區(qū)分大小寫的,例如
和、、的作用是一樣的。如果要從網(wǎng)頁中提取,不使用匹配模式的表達(dá)式應(yīng)該是這樣:由于
標(biāo)簽只有兩個(gè)字符,所以上面的寫法還可以接受。但是如果標(biāo)簽是world';preg_match('/
.*<\/tr>/', $str, $arr);print_r($arr);
/*
Array
(
[0] =>
helloworld)
*/
// 非貪婪匹配模式
$str = '
helloworld';preg_match('/
.*<\/tr>/U', $str, $arr);print_r($arr);
/*
Array
(
[0] =>
hello)
*/
Unicode
要匹配中文等Unicode字符,最好是指定Unicode模式修飾符/.../u。如果不指定會(huì)有兩個(gè)問題
GBK編碼環(huán)境下,中文不能匹配
無法利用[\x{4e00}-\x{9fff}]匹配中文
// 指定unicode模式
preg_match('/
[\x{4e00}-\x{9fff}]*<\/td>/u', '姚明', $arr);print_r($arr);
/*
Array
(
[0] =>
姚明)
*/
總結(jié)
以上是生活随笔為你收集整理的正则环视 php,正则表达式基本知识(php)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 粗粮吃得越多越养胃吗?蚂蚁庄园3.1日答
- 下一篇: 谷歌预告 9 项 Android 和 W