今天用正則表達式的時候遇到了不少問題,就研究了一下,參考了不少博客,特此記錄。
正則表達式的參數 參考
/i (忽略大小寫)
/g (全文查找出現的所有匹配字符)
/m (多行查找)
/gi(全文查找、忽略大小寫)
/ig(全文查找、忽略大小寫)
下面為PCRE模式的修飾符,js不支持。參考
i 模式中的字符將同時匹配大小寫字母
m 字符串視為多行
s 將字符串視為單行,換行符作為普通字符
x 將模式中的空白忽略
e preg_replace() 函數在替換字符串中對逆向引用作正常的替換,將其作為 PHP 代碼求值,並用其結果來替換所搜索的字符串。
A 強制僅從目標字符串的開頭開始匹配
D 模式中的 $ 元字符僅匹配目標字符串的結尾
U 匹配最近的字符串
u 模式字符串被當成 UTF-8
使用正則表達式的方法 參考W3School
RegExp 對象有 3 個方法:test()、exec() 和 compile()。
有兩種方式都可以創建一個RegExp對象。
var re = new RegExp("a","gi");// 匹配所有的a或A var re = /a/gi; // 與前一個相同
RegExp 對象屬性
屬性 | 描述 |
---|---|
global | RegExp 對象是否具有標志 g。 |
ignoreCase | RegExp 對象是否具有標志 i。 |
lastIndex | 一個整數,標示開始下一次匹配的字符位置。 |
multiline | RegExp 對象是否具有標志 m。 |
source | 正則表達式的源文本。 |
RegExp 對象方法
方法 | 描述 |
---|---|
compile | 編譯正則表達式。 |
exec | 檢索字符串中指定的值。返回找到的值,並確定其位置。 |
test | 檢索字符串中指定的值。返回 true 或 false。 |
String 對象有 4 個方法:search()、match()、replace() 和 split()。
支持正則表達式的 String 對象的方法
方法 | 描述 |
---|---|
search | 檢索與正則表達式相匹配的值。 |
match | 找到一個或多個正則表達式的匹配。 |
replace | 替換與正則表達式匹配的子串。 |
split | 把字符串分割為字符串數組。 |
RegExpObject.test(string)
string是必需的。是要檢測的字符串。如果字符串 string 中含有與 RegExpObject 匹配的文本,則返回 true,否則返回 false。調用 RegExp 對象 r 的 test() 方法,並為它傳遞字符串 s,與這個表示式是等價的:(r.exec(s) != null)。
var patt1 = new RegExp("e"); patt1.test("CraryPrimitiveMan");
由於該字符串中存在字母 "e",結果是true
exec() 方法用於檢索字符串中的正則表達式的匹配。
RegExpObject.exec(string)
string是必需的。是要檢測的字符串。返回一個數組,其中存放匹配的結果。如果未找到匹配,則返回值為 null。
exec() 方法的功能非常強大,它是一個通用的方法,而且使用起來也比 test() 方法以及支持正則表達式的 String 對象的方法更為復雜。
如果 exec() 找到了匹配的文本,則返回一個結果數組。否則,返回 null。此數組的第 0 個元素是與正則表達式相匹配的文本,第 1 個元素是與 RegExpObject 的第 1 個子表達式相匹配的文本(如果有的話),第 2 個元素是與 RegExpObject 的第 2 個子表達式相匹配的文本(如果有的話),以此類推。除了數組元素和 length 屬性之外,exec() 方法還返回兩個屬性。index 屬性聲明的是匹配文本的第一個字符的位置。input 屬性則存放的是被檢索的字符串 string。我們可以看得出,在調用非全局的 RegExp 對象的 exec() 方法時,返回的數組與調用方法 String.match() 返回的數組是相同的。
但是,當 RegExpObject 是一個全局正則表達式時,exec() 的行為就稍微復雜一些。它會在 RegExpObject 的 lastIndex 屬性指定的字符處開始檢索字符串 string。當 exec() 找到了與表達式相匹配的文本時,在匹配后,它將把 RegExpObject 的 lastIndex 屬性設置為匹配文本的最后一個字符的下一個位置。這就是說,您可以通過反復調用 exec() 方法來遍歷字符串中的所有匹配文本。當 exec() 再也找不到匹配的文本時,它將返回 null,並把 lastIndex 屬性重置為 0。
var patt1 = new RegExp("e"); patt1.exec("CraryPrimitiveMan");
由於該字符串中存在字母 "e",結果是e。
您可以向 RegExp 對象添加第二個參數,以設定檢索。例如,如果需要找到所有某個字符的所有存在,則可以使用 "g" 參數 ("global")。
在使用 "g" 參數時,exec() 的工作原理如下:
- 找到第一個 "r",並存儲其位置
- 如果再次運行 exec(),則從存儲的位置開始檢索,並找到下一個 "r",並存儲其位置
var patt1 = new RegExp("r","g"); do { result = patt1.exec("CraryPrimitiveMan"); console.log(result); } while (result!=null)
由於這個字符串中 3 個 "r" 字母,代碼的輸出是r r r null
compile() 方法用於改變 RegExp。
compile() 既可以改變檢索模式,也可以添加或刪除第二個參數。
RegExpObject.compile(regexp,modifier)
regexp是正則表達式。modifier是規定匹配的類型。"g" 用於全局匹配,"i" 用於區分大小寫,"gi" 用於全局區分大小寫的匹配。
var patt1 = new RegExp("e"); console.log(patt1.test("CraryPrimitiveMan")); patt1.compile("d"); console.log(patt1.test("CraryPrimitiveMan"));
由於字符串中存在 "e",而沒有 "d",代碼的結果是true false
search() 方法用於檢索字符串中指定的子字符串,或檢索與正則表達式相匹配的子字符串。
stringObject.search(regexp)
regexp可以是需要在 stringObject 中檢索的子串,也可以是需要檢索的 RegExp 對象。返回stringObject 中第一個與 regexp 相匹配的子串的起始位置。如果沒有找到任何匹配的子串,則返回 -1。search() 方法不執行全局匹配,它將忽略標志 g。它同時忽略 regexp 的 lastIndex 屬性,並且總是從字符串的開始進行檢索,這意味着它總是返回 stringObject 的第一個匹配的位置。
var str = "Visit W3School!" console.log(str.search(/W3School/))
返回結果為6。
match() 方法可在字符串內檢索指定的值,或找到一個或多個正則表達式的匹配。
該方法類似 indexOf() 和 lastIndexOf(),但是它返回指定的值,而不是字符串的位置。
stringObject.match(searchvalue)
stringObject.match(regexp)
searchvalue是規定要檢索的字符串值。regexp是規定要匹配的模式的 RegExp 對象。如果該參數不是 RegExp 對象,則需要首先把它傳遞給 RegExp 構造函數,將其轉換為 RegExp 對象。返回存放匹配結果的數組。該數組的內容依賴於 regexp 是否具有全局標志 g。
match() 方法將檢索字符串 stringObject,以找到一個或多個與 regexp 匹配的文本。這個方法的行為在很大程度上有賴於 regexp 是否具有標志 g。
如果 regexp 沒有標志 g,那么 match() 方法就只能在 stringObject 中執行一次匹配。如果沒有找到任何匹配的文本, match() 將返回 null。否則,它將返回一個數組,其中存放了與它找到的匹配文本有關的信息。該數組的第 0 個元素存放的是匹配文本,而其余的元素存放的是與正則表達式的子表達式匹配的文本。除了這些常規的數組元素之外,返回的數組還含有兩個對象屬性。index 屬性聲明的是匹配文本的起始字符在 stringObject 中的位置,input 屬性聲明的是對 stringObject 的引用。
如果 regexp 具有標志 g,則 match() 方法將執行全局檢索,找到 stringObject 中的所有匹配子字符串。若沒有找到任何匹配的子串,則返回 null。如果找到了一個或多個匹配子串,則返回一個數組。不過全局匹配返回的數組的內容與前者大不相同,它的數組元素中存放的是 stringObject 中所有的匹配子串,而且也沒有 index 屬性或 input 屬性。
注意:在全局檢索模式下,match() 即不提供與子表達式匹配的文本的信息,也不聲明每個匹配子串的位置。如果您需要這些全局檢索的信息,可以使用 RegExp.exec()。
var str = "1 plus 2 equal 3" console.log(str.match(/\d+/g))
結果是["1", "2", "3"],是一個數組。
replace() 方法用於在字符串中用一些字符替換另一些字符,或替換一個與正則表達式匹配的子串。
stringObject.replace(regexp/substr,replacement)
regexp/substr是規定的子字符串或要替換的模式的 RegExp 對象。請注意,如果該值是一個字符串,則將它作為要檢索的直接量文本模式,而不是首先被轉換為 RegExp 對象。replacement是一個字符串值。規定了替換文本或生成替換文本的函數。返回一個新的字符串,是用 replacement 替換了 regexp 的第一次匹配或所有匹配之后得到的。
字符串 stringObject 的 replace() 方法執行的是查找並替換的操作。它將在 stringObject 中查找與 regexp 相匹配的子字符串,然后用 replacement 來替換這些子串。如果 regexp 具有全局標志 g,那么 replace() 方法將替換所有匹配的子串。否則,它只替換第一個匹配子串。
replacement 可以是字符串,也可以是函數。如果它是字符串,那么每個匹配都將由字符串替換。但是 replacement 中的 $ 字符具有特定的含義。如下表所示,它說明從模式匹配得到的字符串將用於替換。
字符 | 替換文本 |
---|---|
$1、$2、...、$99 | 與 regexp 中的第 1 到第 99 個子表達式相匹配的文本。 |
$& | 與 regexp 相匹配的子串。 |
$` | 位於匹配子串左側的文本。 |
$' | 位於匹配子串右側的文本。 |
$$ | 直接量符號。 |
ECMAScript v3 規定,replace() 方法的參數 replacement 可以是函數而不是字符串。在這種情況下,每個匹配都調用該函數,它返回的字符串將作為替換文本使用。該函數的第一個參數是匹配模式的字符串。接下來的參數是與模式中的子表達式匹配的字符串,可以有 0 個或多個這樣的參數。接下來的參數是一個整數,聲明了匹配在 stringObject 中出現的位置。最后一個參數是 stringObject 本身。
var str = "Visit Microsoft!" console.log(str.replace(/Microsoft/, "W3School"))
結果是Visit W3School!。
split() 方法用於把一個字符串分割成字符串數組。
stringObject.split(separator,howmany)
separator是字符串或正則表達式,從該參數指定的地方分割 stringObject。howmany是可指定的返回的數組的最大長度。如果設置了該參數,返回的子串不會多於這個參數指定的數組。如果沒有設置該參數,整個字符串都會被分割,不考慮它的長度。返回一個字符串數組。該數組是通過在 separator 指定的邊界處將字符串 stringObject 分割成子串創建的。返回的數組中的字串不包括separator 自身。但是,如果 separator 是包含子表達式的正則表達式,那么返回的數組中包括與這些子表達式匹配的字串(但不包括與整個正則表達式匹配的文本)。
"2:3:4:5".split(":")
返回["2", "3", "4", "5"]
相關符號及描述
正則表達式有多種不同的風格。下表是在PCRE中元字符及其在正則表達式上下文中的行為的一個完整列表,適用於Perl或者Python編程語言(grep或者egrep的正則表達式文法是PCRE的子集):
字符 | 描述 |
---|---|
\ | 將下一個字符標記為一個特殊字符、或一個原義字符、或一個向后引用、或一個八進制轉義符。例如,“n ”匹配字符“n ”。“\n ”匹配一個換行符。串行“\\ ”匹配“\ ”而“\( ”則匹配“( ”。 |
^ | 匹配輸入字符串的開始位置。如果設置了RegExp對象的Multiline屬性,^也匹配“\n ”或“\r ”之后的位置。 |
$ | 匹配輸入字符串的結束位置。如果設置了RegExp對象的Multiline屬性,$也匹配“\n ”或“\r ”之前的位置。 |
* | 匹配前面的子表達式零次或多次。例如,zo*能匹配“z ”以及“zoo ”。*等價於{0,}。 |
+ | 匹配前面的子表達式一次或多次。例如,“zo+ ”能匹配“zo ”以及“zoo ”,但不能匹配“z ”。+等價於{1,}。 |
? | 匹配前面的子表達式零次或一次。例如,“do(es)? ”可以匹配“do ”或“does ”中的“do ”。?等價於{0,1}。 |
{n} | n是一個非負整數。匹配確定的n次。例如,“o{2} ”不能匹配“Bob ”中的“o ”,但是能匹配“food ”中的兩個o。 |
{n,} | n是一個非負整數。至少匹配n次。例如,“o{2,} ”不能匹配“Bob ”中的“o ”,但能匹配“foooood ”中的所有o。“o{1,} ”等價於“o+ ”。“o{0,} ”則等價於“o* ”。 |
{n,m} | m和n均為非負整數,其中n<=m。最少匹配n次且最多匹配m次。例如,“o{1,3} ”將匹配“fooooood ”中的前三個o。“o{0,1} ”等價於“o? ”。請注意在逗號和兩個數之間不能有空格。 |
? | 當該字符緊跟在任何一個其他限制符(*,+,?,{n},{n,},{n,m})后面時,匹配模式是非貪婪的。非貪婪模式盡可能少的匹配所搜索的字符串,而默認的貪婪模式則盡可能多的匹配所搜索的字符串。例如,對於字符串“oooo ”,“o+? ”將匹配單個“o ”,而“o+ ”將匹配所有“o ”。 |
. | 匹配除“\ n ”之外的任何單個字符。要匹配包括“\ n ”在內的任何字符,請使用像“(.|\n) ”的模式。 |
(pattern) | 匹配pattern並獲取這一匹配的子字符串。該子字符串用於向后引用。所獲取的匹配可以從產生的Matches集合得到,在VBScript中使用SubMatches集合,在JScript中則使用$0…$9屬性。要匹配圓括號字符,請使用“\( ”或“\) ”。 |
(?:pattern) | 匹配pattern但不獲取匹配的子字符串,也就是說這是一個非獲取匹配,不存儲匹配的子字符串用於向后引用。這在使用或字符“(|) ”來組合一個模式的各個部分是很有用。例如“industr(?:y|ies) ”就是一個比“industry|industries ”更簡略的表達式。 |
(?=pattern) | 正向肯定預查,在任何匹配pattern的字符串開始處匹配查找字符串。這是一個非獲取匹配,也就是說,該匹配不需要獲取供以后使用。例如,“Windows(?=95|98|NT|2000) ”能匹配“Windows2000 ”中的“Windows ”,但不能匹配“Windows3.1 ”中的“Windows ”。預查不消耗字符,也就是說,在一個匹配發生后,在最后一次匹配之后立即開始下一次匹配的搜索,而不是從包含預查的字符之后開始。 |
(?!pattern) | 正向否定預查,在任何不匹配pattern的字符串開始處匹配查找字符串。這是一個非獲取匹配,也就是說,該匹配不需要獲取供以后使用。例如“Windows(?!95|98|NT|2000) ”能匹配“Windows3.1 ”中的“Windows ”,但不能匹配“Windows2000 ”中的“Windows ”。預查不消耗字符,也就是說,在一個匹配發生后,在最后一次匹配之后立即開始下一次匹配的搜索,而不是從包含預查的字符之后開始 |
(?<=pattern) | 反向肯定預查,與正向肯定預查類似,只是方向相反。例如,“(?<=95|98|NT|2000)Windows ”能匹配“2000Windows ”中的“Windows ”,但不能匹配“3.1Windows ”中的“Windows ”。 |
(?<!pattern) | 反向否定預查,與正向否定預查類似,只是方向相反。例如“(?<!95|98|NT|2000)Windows ”能匹配“3.1Windows ”中的“Windows ”,但不能匹配“2000Windows ”中的“Windows ”。 |
x|y | 匹配x或y。例如,“z|food ”能匹配“z ”或“food ”。“(z|f)ood ”則匹配“zood ”或“food ”。 |
[xyz] | 字符集合(character class)。匹配所包含的任意一個字符。例如,“[abc] ”可以匹配“plain ”中的“a ”。特殊字符僅有反斜線\保持特殊含義,用於轉義字符。其它特殊字符如星號、加號、各種括號等均作為普通字符。脫字符^如果出現在首位則表示負值字符集合;如果出現在字符串中間就僅作為普通字符。連字符 - 如果出現在字符串中間表示字符范圍描述;如果如果出現在首位則僅作為普通字符。 |
[^xyz] | 排除型(negate)字符集合。匹配未列出的任意字符。例如,“[^abc] ”可以匹配“plain ”中的“plin ”。 |
[a-z] | 字符范圍。匹配指定范圍內的任意字符。例如,“[a-z] ”可以匹配“a ”到“z ”范圍內的任意小寫字母字符。 |
[^a-z] | 排除型的字符范圍。匹配任何不在指定范圍內的任意字符。例如,“[^a-z] ”可以匹配任何不在“a ”到“z ”范圍內的任意字符。 |
\b | 匹配一個單詞邊界,也就是指單詞和空格間的位置。例如,“er\b ”可以匹配“never ”中的“er ”,但不能匹配“verb ”中的“er ”。 |
\B | 匹配非單詞邊界。“er\B ”能匹配“verb ”中的“er ”,但不能匹配“never ”中的“er ”。 |
\cx | 匹配由x指明的控制字符。例如,\cM匹配一個Control-M或回車符。x的值必須為A-Z或a-z之一。否則,將c視為一個原義的“c ”字符。 |
\d | 匹配一個數字字符。等價於[0-9]。 |
\D | 匹配一個非數字字符。等價於[^0-9]。 |
\f | 匹配一個換頁符。等價於\x0c和\cL。 |
\n | 匹配一個換行符。等價於\x0a和\cJ。 |
\r | 匹配一個回車符。等價於\x0d和\cM。 |
\s | 匹配任何空白字符,包括空格、制表符、換頁符等等。等價於[ \f\n\r\t\v]。 |
\S | 匹配任何非空白字符。等價於[^ \f\n\r\t\v]。 |
\t | 匹配一個制表符。等價於\x09和\cI。 |
\v | 匹配一個垂直制表符。等價於\x0b和\cK。 |
\w | 匹配包括下划線的任何單詞字符。等價於“[A-Za-z0-9_] ”。 |
\W | 匹配任何非單詞字符。等價於“[^A-Za-z0-9_] ”。 |
\xn | 匹配n,其中n為十六進制轉義值。十六進制轉義值必須為確定的兩個數字長。例如,“\x41 ”匹配“A ”。“\x041 ”則等價於“\x04&1 ”。正則表達式中可以使用ASCII編碼。. |
\num | 向后引用(back-reference)一個子字符串(substring),該子字符串與正則表達式的第num個用括號圍起來的子表達式(subexpression)匹配。其中num是從1開始的正整數,其上限可能是99。例如:“(.)\1 ”匹配兩個連續的相同字符。 |
\n | 標識一個八進制轉義值或一個向后引用。如果\n之前至少n個獲取的子表達式,則n為向后引用。否則,如果n為八進制數字(0-7),則n為一個八進制轉義值。 |
\nm | 標識一個八進制轉義值或一個向后引用。如果\nm之前至少有nm個獲得子表達式,則nm為向后引用。如果\nm之前至少有n個獲取,則n為一個后跟文字m的向后引用。如果前面的條件都不滿足,若n和m均為八進制數字(0-7),則\nm將匹配八進制轉義值nm。 |
\nml | 如果n為八進制數字(0-3),且m和l均為八進制數字(0-7),則匹配八進制轉義值nml。 |
\un | 匹配n,其中n是一個用四個十六進制數字表示的Unicode字符。例如,\u00A9匹配版權符號(©)。 |
匹配次數中的貪婪與非貪婪
貪婪模式:
在使用修飾匹配次數的特殊符號時,有幾種表示方法可以使同一個表達式能夠匹配不同的次數,比如:"{m,n}", "{m,}", "?", "*", "+",具體匹配的次數隨被匹配的字符串而定。這種重復匹配不定次數的表達式在匹配過程中,總是盡可能多的匹配。比如,針對文本 "dxxxdxxxd",舉例如下:
表達式 |
匹配結果 |
"\w+" 將匹配第一個 "d" 之后的所有字符 "xxxdxxxd" |
|
"\w+" 將匹配第一個 "d" 和最后一個 "d" 之間的所有字符 "xxxdxxx"。雖然 "\w+" 也能夠匹配上最后一個 "d",但是為了使整個表達式匹配成功,"\w+" 可以 "讓出" 它本來能夠匹配的最后一個 "d" |
由此可見,"\w+" 在匹配的時候,總是盡可能多的匹配符合它規則的字符。雖然第二個舉例中,它沒有匹配最后一個 "d",但那也是為了讓整個表達式能夠匹配成功。同理,帶 "*" 和 "{m,n}" 的表達式都是盡可能地多匹配,帶 "?" 的表達式在可匹配可不匹配的時候,也是盡可能的 "要匹配"。這 種匹配原則就叫作 "貪婪" 模式 。
非貪婪模式:
在修飾匹配次數的特殊符號后再加上一個 "?" 號,則可以使匹配次數不定的表達式盡可能少的匹配,使可匹配可不匹配的表達式,盡可能的 "不匹配"。這種匹配原則叫作 "非貪婪" 模式,也叫作 "勉強" 模式。如果少匹配就會導致整個表達式匹配失敗的時候,與貪婪模式類似,非貪婪模式會最小限度的再匹配一些,以使整個表達式匹配成功。舉例如下,針對文本 "dxxxdxxxd" 舉例:
表達式 |
匹配結果 |
"\w+?" 將盡可能少的匹配第一個 "d" 之后的字符,結果是:"\w+?" 只匹配了一個 "x" |
|
為了讓整個表達式匹配成功,"\w+?" 不得不匹配 "xxx" 才可以讓后邊的 "d" 匹配,從而使整個表達式匹配成功。因此,結果是:"\w+?" 匹配 "xxx" |
經典例子
例1:JavaScript(?:)
var x = /^([Jj]ava(?:[Ss]cript)?)$/, y = /^([Jj]ava([Ss]cript)?)$/, z = 'javascript'; z.match(x);//結果為["javascript", "javascript"] z.match(y);//結果為["javascript", "javascript", "script"]
例2:JavaScript(\1)
var words = "This is a block of of text.", reg = /[ ]+(\w+)[ ]+\1/; words.match(reg) //結果為[" of of", "of"]
“[ ]+ ”匹配一個或者更多空格,“\w+”匹配一個或者更多的文字數字式字符,而“[ ]+”則用來匹配尾部的空格。但是注意到這里的“ \w+ ”加上了括號使其成為子表達式。此子表達式並不是用於重復匹配,而且本例中也不需要重復。這里的子表達式僅僅是對表達式進行分組,標記此子表達式供以后使用。模式的最后部分是“ \1 ”,這是對子表達式的后向引用,所以當“ \w+ ”匹配了單詞 of ,“ \1 ”也將匹配 of ,當“ \w+ ”匹配了單詞 and ,“ \1 ”也將匹配 and 。
注意:術語后向應用是因為這些實體將引用以前的子表達式。
但是“ \1 ”的實際含義是什么呢?它匹配模式中第一個子表達式。同理,“ \2 ”將匹配第二個子表達式,“ \3 ”將匹配第四個,依此類推。“[ ]+(\w+)[ ]+\1”因此將可以匹配所有重復出現的單詞。
例3:貪婪模式與非貪婪模式
try{ str="<p>abcdefg</p><p>abcdefghijkl</p>"; re1 = str.match(/<p>[\W\w]+?<\/p>/ig); console.log("非貪婪模式:\r\n\r\n1:"+re1[0]+"\r\n2:"+re1[1]); re1 = str.match(/<p>[\W\w]+<\/p>/ig); console.log("貪婪模式:\r\n\r\n"+re1); re1 = str.match(/<p>(.+?)<\/p>/i); console.log("非貪婪模式,且不要標記:\r\n\r\n1:"+re1[1]); re1 = str.match(/<p>(.+)<\/p>/i); console.log("貪婪模式,且不要標記:\r\n\r\n"+re1[1]); } catch(e){ console.log(e.description) }
運行結果:
解決方法:
(1) 可以不使用g(全局參數)
var objReg = /^[a-zA-Z]{1}(:){1}$/i; console.log(objReg.test("a:"));//返回true console.log(objReg.test("a:"));//返回true
(2) 可以用lastIndex=0來還原
var objReg = /^[a-zA-Z]{1}(:){1}$/gi; console.log(objReg.test("a:"));//返回true objReg.lastIndex = 0; console.log(objReg.test("a:"));//返回true
推薦JavaScript正則表達式解析工具 http://jex.im/regulex/
該項目github地址 https://github.com/JexCheng/regulex
正則表達式暫時到這里,如有問題,請留言指正~~