摘要:字符組字符組就是一組字符,在正則表達(dá)式中,它表示在同一個位置可能出現(xiàn)的各種字符。放在正則表達(dá)式的開頭,表示定位到字符串的起始位置用在正則表達(dá)式的末尾,表示定位到字符串的結(jié)束位置。
這里的知識點基本上是《正則指引》的讀書筆記,只是每個知識點的示例代碼用php來實現(xiàn)。
1. 字符組字符組的基本用法字符組(Character Class)就是一組字符,在正則表達(dá)式中,它表示“在同一個位置可能出現(xiàn)的各種字符”。
寫法:[ab]、[314]、[#.?]
[...]
preg_match("/[0123456]/", "5"); // => 1 preg_match("/[abc123]/", "5"); // => 0范圍表示法(range)
[x-y]表示x到y整個范圍內(nèi)的字符。如,[0123456789]表示為[0-9],[abcdefghijk]表示為[a-k]。
為什么是[0-9],而不是[9-0]?
因為-表示的范圍一般是根據(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/", " "); // => 1 preg_match("/s/", " "); // => 1元字符與轉(zhuǎn)義
在范圍表示法中,字符組中的橫線-不能匹配橫線字符,而是用來表示范圍,這類字符叫做元字符(meta-character)。元字符除了-還有開方括號[、閉剛括號]、^、$等,它們都有特殊的意義。
當(dāng)元字符想要表示普通字符的含義時(如-就只想表示橫線字符),就需要轉(zhuǎn)義處理(在元字符前加反斜線字符)。對于-,有一個例外情況,就是當(dāng)它緊跟著字符組中的開括號[時,它就表示普通橫線字符,此時不用轉(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ì)看上面第一個表達(dá)式和最后兩個表示式。這里要注意:
在php中,字符串既可以用單引號標(biāo)注也可以用雙引號標(biāo)注。兩者的主要區(qū)別在于,雙引號字符串可以插值,二單引號字符串不能;另外,雙引號字符串會處理字符串轉(zhuǎn)義,二單引號字符串不會
正則表達(dá)式是以字符串的方式提供的。在php中,雙引號字符串本身也有關(guān)于轉(zhuǎn)義的規(guī)定(如""、" "、" "等),因此"0-9"與"0-9"是等價的。
那么最后一個表達(dá)式為什么也可以匹配呢?這是因為,盡管php的正則表達(dá)式用字符串文字給出,但它與常見的字符串不完全一樣——如果某個轉(zhuǎn)義序列可以有字符串識別,則對其進(jìn)行轉(zhuǎn)義處理;否則,將整個轉(zhuǎn)義序列“原封不動”地保存下來。
因此,在正則表達(dá)式中轉(zhuǎn)義要小心,在php中,使用單引號字符串來構(gòu)建正則表達(dá)式會比雙引號字符串更簡單明了。
排除型字符組(Negated Character Class)在方括號[…]中列出希望匹配的所有字符叫做“普通字符組”。在開方括號[之后緊跟一個脫字符^,寫作[^…],表示“在當(dāng)前位置,匹配一個沒有列出的字符”。例如,[^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^]/", "^"); // => 1POSIX字符組
之前介紹的字符組,都屬于Perl衍生出來的正則表達(dá)式流派(Flavor),這個流派叫做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兩個字符。這里涉及到]、-這兩個特殊字符,在POSIX規(guī)范中,緊接在開方括號[之后的]才表示閉方括號字符,緊挨在閉方括號]之前的-才表示橫線字符。
對于PCRE規(guī)范中的d、w、s等字符組簡記法,POSIX中有類似的東西,叫做POSIX字符組。在ASCⅡ語言環(huán)境(locale)中,常見的POSIX字符組及其含義如下:
POSIX字符組 | 說明 | ACSⅡ字符組 | 等價的PCRE簡記法 |
---|---|---|---|
[:alnum:] | 字母和數(shù)字 | [0-9a-zA-Z] | |
[:alpha:] | 字母 | [a-zA-Z] | |
[:ASCⅡ] | ASCⅡ字符 | [x00-x7F] | |
[:blank:] | 空格字符和制表字符 | [ ] | |
[:cntrl:] | 控制字符 | [x00-x1Fx7F] | |
[:digit:] | 數(shù)字字符 | [0-9] | d |
[:graph:] | 空白字符之外的字符 | [x21-x7E] | |
[:lower:] | 小寫字母字符 | [a-z] | |
[:print:] | 類似[:graph:],但包括空白字符 | [x20-x7E] | |
[:punct:] | 標(biāo)點符號 | [][!"#$%&"()*+,./:;<=>?@^_`{ | }~-] |
[:space:] | 空白字符 | [ vf] | 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. 量詞這里首先介紹一下^和$兩個特殊字符,在上一章的元字符與轉(zhuǎn)義一節(jié)提到過這兩個特殊字符。
^放在正則表達(dá)式的開頭,表示“定位到字符串的起始位置”;$用在正則表達(dá)式的末尾,表示“定位到字符串的結(jié)束位置”。
preg_match("/wd/", "1a2b"); // => 1 preg_match("/^wd/", "1a2b"); // => 0 必須以字母開頭 preg_match("/wd$/", "1a2b"); // => 0 必須以數(shù)字結(jié)尾 preg_match("/^wd/", "a2b"); // => 1 preg_match("/wd$/", "1a2"); // => 1 preg_match("/^wd$/", "1a2"); // => 0 開頭必須是字母,結(jié)尾必須是數(shù)字 preg_match("/^wd$/", "a2"); // => 1量詞的一般形式
如果要匹配一個郵政編碼(6位數(shù)字),目前能寫出來的正則表達(dá)式是^ffffdffffd$:
preg_match("/^ffffdffffd$/", "100010"); // => 1 preg_match("/^ffffdffffd$/", "10001035"); // => 0 preg_match("/^ffffdffffd$/", "10a010"); // => 0
d重復(fù)6次的寫法很不科學(xué),正則表達(dá)式肯定會有更方便的寫法,也就是量詞(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á)式還有三個常用的量詞,分別是+、?、*:
常用量詞 | {m,n}等價形式 | 說明 |
---|---|---|
* | {0,} | 可能出現(xiàn),也可能不出現(xiàn),出現(xiàn)次數(shù)沒有上限 |
+ | {1,} | 至少出現(xiàn)1次,出現(xiàn)次數(shù)沒有上限 |
? | {0,1} | 出現(xiàn)0次或1次 |
這三種量詞在實際中使用的非常多。
例如,匹配url的時候,有可能是http,也有可能是https,這個時候用?就很方便:
preg_match("/^https?://www.baidu.com/", "http://www.baidu.com"); // => 1 preg_match("/^https?://www.baidu.com/", "https://www.baidu.com"); // => 1
在匹配html的tag(如、 <(?!/).*+(? 上面的正則表達(dá)式中有兩個環(huán)視結(jié)構(gòu),一個在開尖括號<之后,表示在尖括號<后向右看看,右邊的第一個字符不能為/(正則表達(dá)式中進(jìn)行了轉(zhuǎn)義);另外一個在閉尖括號>之前,表示在閉尖括號>之前向左看看,左邊挨著的字符不能為/。 上面的正則表達(dá)式已經(jīng)解決了匹配html中開標(biāo)簽的主要問題,只是其中的.*?還需要優(yōu)化一下。需要解決的問題是: 有可能會有單引號"或雙引號",它們都得成對出現(xiàn) 單引號對或雙引號對之內(nèi)可以有>字符,但是它們的外面不能有>字符 利用正則表達(dá)式的選擇結(jié)構(gòu),可以寫出下面的表達(dá)式,用于完善上面的問題。 <(?!/)(?:"[^"]*"|"[^"]*"|[^"">])+(? 前面的內(nèi)容中已經(jīng)出現(xiàn)介過了單行模式、多行模式、非貪婪模式。匹配模式是指匹配時使用的規(guī)則。常用的匹配模式還有不區(qū)分大小寫模式、注釋模式。 在開始介紹具體的模式之前,先介紹php中模式的兩種具體實現(xiàn)/.../{modifier}和...(?{modifier})...: 在html中是不區(qū)分大小寫的,例如 <[tT][dD]> 由于
直接使用<[^/]+>將/字符排除是不對的,因為有些標(biāo)簽的屬性中可能會含有/字符。例如。這里只是在開尖括號<之后的第一個字符和閉尖括號>之前的第一個字符不能為/。
然而<[^/][^>]*[^/]>也是不行的,因為在<與>之間會至少匹配兩個字符,像這樣的標(biāo)簽是無法匹配到的。這里就要用到環(huán)視了。
不區(qū)分大小寫模式
模式修飾符
/.../{modifier}
...(?{modifier})...
示例
/
.* /s(?s).*
名稱(php手冊)
模式修飾符
模式內(nèi)修飾符
名稱(《正則指引》)
預(yù)定義常量
模式修飾符
作用范圍
整個正則表達(dá)式
不在分組(子表達(dá)式)中時,對它后面的全部正則表達(dá)式起作用;如果在分組(子表達(dá)式)中,則對它分組中的剩余部分起作用。在沒有分組,且放在整個正則表達(dá)式最前面的時候相當(dāng)于/.../{modifier}
支持程度
支持所有模式修飾符
支持部分模式修飾符
其他編程語言
可能不支持
一般都支持
和 、 、 的作用是一樣的。如果要從網(wǎng)頁中提取 ,不使用匹配模式的表達(dá)式應(yīng)該是這樣:
標(biāo)簽只有兩個字符,所以上面的寫法還可以接受。但是如果標(biāo)簽是