RegExphtml
Regular Expression,正則表達式是一種表達 文本模式(字符串結構) 的式子。web
經常用來按照「給定模式」匹配文本。好比,正則表達式給出一個 Email 地址的模式,而後用它來肯定一個字符串是否爲 Email 地址。正則表達式
JavaScript 的正則表達式體系是參照 Perl 5 創建的數組
var regex = /xyz/;
var regex = /xyz/ig; // i 和 g 爲兩個修飾符
var regex = new RegExp('xyz');
var regex = new RegExp('xyz', 'i'); // i 和 g 爲兩個修飾符
RegExp.prototype.lastIndex
返回一個整數,表示下一次開始搜索的位置。該屬性可讀寫,可是隻在進行連續搜索時有意義RegExp.prototype.source
返回正則表達式的字符串形式(不包括反斜槓),該屬性只讀
/a/
匹配a
,/b/
匹配b
),那麼它們就叫作「字面量字符」(literal characters)。.
)匹配除回車(\r
)、換行(\n
) 、行分隔符(\u2028
)和段分隔符(\u2029
)之外的全部字符0xFFFF
字符,點字符不能正確匹配,會認爲這是兩個字符^ 表示字符串的開始位置網絡
$ 表示字符串的結束位置app
|
)
/11|22/.test('911'); // true 指定必須匹配到 或 1122
/ab|cd/
指的是匹配ab
或者cd
,而不是指匹配b
或者c
/a( |\t)b/.test('a\tb'); // true
\
、\*
、+
、?
、()
、[]
、{}
等等,將在下文解釋
+
,就要寫成\+
^
.
[
$
(
)
|
*
+
?
{
\
RegExp
方法生成正則對象,轉義須要使用兩個斜槓,由於字符串內部會先轉義一次
(new RegExp('1\+1')).test('1+1'); // false (new RegExp('1\\+1')).test('1+1'); // true
// 做爲構造函數,參數是一個字符串。可是,在字符串內部,反斜槓也是轉義字符,因此它會先被反斜槓轉義一次,而後再被正則表達式轉義一次,所以須要兩個反斜槓轉義
對一些不能打印的特殊字符,提供了表達方法函數
\cX 用來匹配控制字符,表示Ctrl-[X],其中的X是A-Z之中任一個英文字母,
ui
[\b] 匹配退格鍵(U+0008),不要與\b混淆google
\n 匹配換行鍵編碼
\r 匹配回車鍵
\t 匹配製表符 tab(U+0009)
\v 匹配垂直製表符(U+000B)
\f 匹配換頁符(U+000C)
\0 匹配null字符(U+0000)
\xhh 匹配一個以兩位十六進制數(\x00-\xFF)表示的字符
\uhhhh 匹配一個以四位十六進制數(\u0000-\uFFFF)表示的 Unicode 字符
[ ] 表示有一系列字符可供選擇,只要匹配其中一個就能夠了
全部可供選擇的字符都放在方括號內,
好比[xyz]
表示x
、y
、z
之中任選一個匹配
[^]
,則表示除了字符類之中的字符,其餘字符均可以匹配[^xyz]
表示除了x
、y
、z
以外均可以匹配[^]
,就表示匹配一切字符,其中包括換行符
.
)是不包括換行符的
var s = 'Please yes\nmake my day!'; s.match(/yes.*day/); // null 含有一個換行符,點號不包括換行符,因此第一個正則表達式匹配失敗 s.match(/yes[^]*day/); // [ 'yes\nmake my day'] 包含一切字符,因此匹配成功s[^]
[abc]
能夠寫成[a-c]
,[0123456789]
能夠寫成[0-9]
,同理[A-Z]
表示26個大寫字母[A-z]
,表面上它是選中從大寫的A
到小寫的z
之間52個字母,可是因爲在 ASCII 編碼之中,大寫字母與小寫字母之間還有其餘字符,結果就會出現意料以外的結果var str = "\u0130\u0131\u0132"; /[\u0128-\uFFFF]/.test(str); // true // \u0128-\uFFFF 表示匹配碼點在0128到FFFF之間的全部字符
指的是某些常見模式的簡寫方式
\d 匹配0-9之間的任一數字,至關於 [0-9]
\D 匹配全部0-9之外的字符,至關於 [^0-9]
\w 匹配任意的字母、數字和下劃線,至關於 [A-Za-z0-9_]
\W 除全部字母、數字和下劃線之外的字符,至關於 [^A-Za-z0-9_]
\s 匹配空格(包括換行符、製表符、空格符等),相等於[ \t\r\n\v\f]
var html = "<b>Hello</b>\n<i>world!</i>"; /[\S\s]*/.exec(html)[0]; // "<b>Hello</b>\n<i>world!</i>" // [\S\s]指代一切字符
\S 匹配非空格的字符,至關於[^ \t\r\n\v\f]
\b 匹配詞的邊界
\B 匹配非詞邊界,即在詞的內部
// \s 的例子 /\s\w*/.exec('hello world'); // [" world"] // \b 的例子 /\bworld/.test('hello world'); // true /\bworld/.test('hello-world'); // true /\bworld/.test('helloworld'); // false // \B 的例子 /\Bworld/.test('hello-world'); // false /\Bworld/.test('helloworld'); // true
模式的精確匹配次數,使用大括號 { } 表示重複類
{n}
表示剛好重複n
次,
{n,}
表示至少重複n
次,
{n,m}
表示重複很多於n
次,很少於m
次
/lo{2}k/.test('look'); // true 指定o連續出現2次 /lo{2,5}k/.test('looook'); // true 指定o連續出現2次到5次之間
用來設定某個模式出現的次數
? 問號表示某個模式出現0次或1次,等同於{0, 1}
* 星號表示某個模式出現0次或屢次,等同於{0,}
+ 加號表示某個模式出現1次或屢次,等同於{1,}
// t 出現0次或1次 /t?est/.test('test'); // true /t?est/.test('est'); // true // t 出現1次或屢次 /t+est/.test('test'); // true /t+est/.test('ttest'); // true /t+est/.test('est'); // false // t 出現0次或屢次 /t*est/.test('test'); // true /t*est/.test('ttest'); // true /t*est/.test('tttest'); // true /t*est/.test('est'); // true
默認狀況下都是最大可能匹配,即匹配直到下一個字符不知足匹配規則爲止。這被稱爲貪婪模式
var s = 'aaa'; s.match(/a+/); // ["aaa"] // 模式是/a+/,表示匹配1個a或多個a,那麼到底會匹配幾個a呢? // 由於默認是貪婪模式,會一直匹配到字符a不出現爲止,因此匹配結果是3個a
var s = 'aaa'; s.match(/a+?/) // ["a"] 模式結尾添加了一個問號/a+?/,這時就改成非貪婪模式,一旦條件知足,就再也不往下匹配
表示模式的附加規則,放在正則模式的最尾部
能夠單個使用,也能夠多個一塊兒使用
// 正則模式含有g修飾符,每次都是從上一次匹配成功處,開始向後匹配。 var regex = /b/g; var str = 'abba'; regex.test(str); // true regex.test(str); // true regex.test(str); // false // 由於字符串abba只有兩個b,因此前兩次匹配結果爲true,第三次匹配結果爲false
i
修飾符之後表示忽略大小寫(ignorecase)
/abc/.test('ABC'); // false /abc/i.test('ABC'); // true // 加了i修飾符之後,不考慮大小寫,因此模式abc匹配字符串ABC
^
和 $
的行爲m
修飾符之後,^
和 $
還會匹配行首和行尾,即 ^
和 $
會識別換行符(\n
)
/world$/.test('hello world\n'); // false /world$/m.test('hello world\n'); // true // 字符串結尾處有一個換行符。若是不加m修飾符,匹配不成功,由於字符串的結尾不是world;加上之後,$能夠匹配行尾
/^b/m.test('a\nb'); // true
// 若是不加m
修飾符,就至關於b
只能處在字符串的開始處。加上b
修飾符之後,換行符\n
也會被認爲是一行的開始mbb\n
括號表示分組匹配,括號中的模式能夠用來匹配分組的內容
/fred+/.test('fredd'); // true 結果+只表示重複字母d /(fred)+/.test('fredfred'); // true 有括號,結果+就表示匹配fred這個詞
g
修飾符,不然match
方法不會捕獲分組的內容
var m = 'abcabc'.match(/(.)b(.)/g); m // ['abc', 'abc'] // 帶 g 修飾符的正則表達式,結果match方法只捕獲了匹配整個表達式的部分 // 這時必須使用正則表達式的exec方法,配合循環,才能讀到每一輪匹配的組捕獲 var str = 'abcabc'; var reg = /(.)b(.)/g; while (true) { var result = reg.exec(str); if (!result){ break; } console.log(result); } // ["abc", "a", "c"] // ["abc", "a", "c"]
/(.)b(.)\1b\2/.test("abcabc"); // true
/y((..)\2)\1/.test('yabababab'); // true 指向外層括號,指向內層括號\1\2
var tagName = /<([^>]+)>[^<]*<\/\1>/; // 圓括號 匹配 尖括號之中的標籤,就表示 對應的閉合標籤 tagName.exec("<b>bold</b>")[1]; // 'b'\1
var html = '<b class="hello">Hello</b><i>world</i>'; var tag = /<(\w+)([^>]*)>(.*?)<\/\1>/g; var match = tag.exec(html); match[1] // "b" match[2] // " class="hello"" match[3] // "Hello" match = tag.exec(html); match[1] // "i" match[2] // "" match[3] // "world"
表示不返回該組匹配的內容,即這個括號中匹配的內容不計入結果
foo
或者foofoo
,正則表達式就應該寫成/(foo){1, 2}/
,可是這樣會佔用一個組匹配。這時,就可使用非捕獲組,將正則表達式改成/(?:foo){1, 2}/
,它的做用與前一個正則是同樣的,可是不會單獨輸出括號內部的內容
var m = 'abc'.match(/(?:.)b(.)/); m // ["abc", "c"] // 第一個括號是非捕獲組,因此最後返回的結果中沒有第一個括號,只有第二個括號匹配的內容
// 正常匹配 第一個括號返回網絡協議 var url = /(http|ftp):\/\/([^/\r\n]+)(\/[^\r\n]*)?/; url.exec('http://google.com/'); // ["http://google.com/", "http", "google.com", "/"]
// 非捕獲組匹配 返回結果中不包括網絡協議 var url = /(?:http|ftp):\/\/([^/\r\n]+)(\/[^\r\n]*)?/; url.exec('http://google.com/'); // ["http://google.com/", "google.com", "/"]
x
只有在 y前面才匹配,y 不會被計入返回結果。即括號裏的部分是不會返回的
好比,要匹配後面跟着百分號的數字,能夠寫成/\d+(?=%)/
。
var m = 'abc'.match(/b(?=c)/); m // ["b"] 使用了先行斷言,b在c前面因此被匹配,可是括號對應的c不會被返回
只有不在y
前面才匹配,y
不會被計入返回結果。即括號裏的部分是不會返回的
好比,要匹配後面跟的不是百分號的數字,就要寫成/\d+(?!%)/
/\d+(?!\.)/.exec('3.14') // ["14"]
b
不在c
前面因此被匹配,並且括號對應的d
不會被返回
var m = 'abd'.match(/b(?!c)/); m // ['b']
/cat/.test('cats and dogs'); // true 驗證參數字符串之中是否包含 cat
g
修飾符時,能夠經過正則對象的 lastIndex
屬性指定開始搜索的位置var r = /x/g; var s = '_x_x'; r.lastIndex // 0 r.test(s) // true r.lastIndex // 2 r.test(s) // true r.lastIndex // 4 r.test(s) // false
lastIndex
屬性只對同一個正則表達式有效,因此下面這樣寫是錯誤的
var count = 0; while (/a/g.test('babaa')){ count++; } // 無限循環,由於while循環的每次匹配條件都是一個新的正則表達式,致使lastIndex屬性老是等於0
null
var s = '_x_x'; var r1 = /x/; var r2 = /y/; r1.exec(s); // ["x"] r2.exec(s); // null
length
屬性等於組匹配的數量再加1var s = '_x_x'; var r = /_(x)/; r.exec(s); // ["_x", "x"] 返回一個數組。第一個成員是整個匹配的結果,第二個成員是圓括號匹配的結果。
exec
方法的返回數組還包含如下兩個屬性:
var r = /a(b+)a/; var arr = r.exec('_abbba_aba_'); arr // ["abbba", "bbb"] arr.index // 1 屬性等於1,是由於從原字符串的第二個位置開始匹配成功 arr.input // "_abbba_aba_"index
g
修飾符,則可使用屢次exec
方法,下一次搜索的位置從上一次匹配成功結束的位置開始
var reg = /a/g; var str = 'abc_abc_abc' var r1 = reg.exec(str); r1 // ["a"] r1.index // 0 reg.lastIndex // 1 var r2 = reg.exec(str); r2 // ["a"] r2.index // 4 reg.lastIndex // 5 var r3 = reg.exec(str); r3 // ["a"] r3.index // 8 reg.lastIndex // 9 var r4 = reg.exec(str); r4 // null reg.lastIndex // 0
// 前三次都是從上一次匹配結束的位置向後匹配。
// 當第三次匹配結束之後,整個字符串已經到達尾部,匹配結果返回,正則實例對象的屬性也重置爲,意味着第四次匹配將從頭開始nulllastIndex0
利用g
修飾符容許屢次匹配的特色,能夠用一個循環完成所有匹配
var reg = /a/g; var str = 'abc_abc_abc' while(true) { var match = reg.exec(str); // 匹配到末尾,匹配失敗,返回 null if (!match) break; console.log('#' + match.index + ':' + match[0]); } // #0:a // #4:a // #8:a
在字符串中有 4 中與正則表達式相關的實例方法。
exec
方法很是相似:匹配成功返回一個數組,匹配失敗返回 null
g
修飾符,會一次性返回全部匹配成功的結果lastIndex
屬性,對match
方法無效
var s = '_x_x'; var r1 = /x/; var r2 = /y/; s.match(r1); // ["x"] s.match(r2); // null ////////////////////////////////////// var s = 'abba'; var r = /a/g; s.match(r); // ["a", "a"] 一次性返回搜索到的結果 r.exec(s); // ["a"] 一次返回只有一個結果的一個數組 lastIndex 後移
-1
'_x_x'.search(/x/); // 1 第一個匹配結果出如今字符串的1號位置
str.replace(search, replacement);
'aaa'.replace('a', 'b'); // "baa" 'aaa'.replace(/a/, 'b'); // "baa" 'aaa'.replace(/a/g, 'b'); // "bbb" 使用了修飾符,致使全部的都被替換掉了gb
g
修飾符,就替換第一個匹配成功的值,不然替換全部匹配成功的值var str = ' #id div.class '; str.replace(/^\s+|\s+$/g, ''); // "#id div.class"
replace
方法的第二個參數可使用美圓符號$
,用來指代所替換的內容
$& 匹配的子字符串。 $` 匹配結果前面的文本。 $' 匹配結果後面的文本。 $n 匹配成功的第n組內容,n是從1開始的天然數。 $$ 指代美圓符號$。
'hello world'.replace(/(\w+)\s(\w+)/, '$2 $1'); // "world hello" 'abc'.replace('b', '[$`-$&-$\']'); // "a[a-b-c]c"
'3 and 5'.replace(/[0-9]+/g, function (match) { return 2 * match; }) // "6 and 10" var a = 'The quick brown fox jumped over the lazy dog.'; var pattern = /quick|brown|lazy/ig; a.replace(pattern, function replacer(match) { return match.toUpperCase(); }); // The QUICK BROWN fox jumped over the LAZY dog.
replace
方法第二個參數的替換函數,能夠接受多個參數。
var prices = { 'p1': '$1.99', 'p2': '$9.99', 'p3': '$5.00' }; var template = '<span id="p1"></span>' + '<span id="p2"></span>' + '<span id="p3"></span>'; template.replace( /(<span id=")(.*?)(">)(<\/span>)/g, function(match, $1, $2, $3, $4){ // 有四個括號,因此會產生四個組匹配,在匹配函數中用到表示。匹配函數的做用是將價格插入模板中 return $1 + $2 + $3 + prices[$2] + $4; } ); // "<span id="p1">$1.99</span><span id="p2">$9.99</span><span id="p3">$5.00</span>"$1$4
str.split(separator, [limit]);
// 非正則分隔 'a, b,c, d'.split(','); // [ 'a', ' b', 'c', ' d' ] // 正則分隔,去除多餘的空格 'a, b,c, d'.split(/, */); // [ 'a', 'b', 'c', 'd' ] // 指定返回數組的最大成員 'a, b,c, d'.split(/, */, 2); [ 'a', 'b' ]
// 例一 'aaa*a*'.split(/a*/); // [ '', '*', '*' ] // 分割規則是0次或屢次的a,因爲正則默認是貪婪匹配,因此例一的第一個分隔符是aaa,第二個分割符是a,將字符串分紅三個部分,包含開始處的空字符串 // 例二 'aaa**a*'.split(/a*/); // ["", "*", "*", "*"] // 第一個分隔符是aaa,第二個分隔符是0個a(即空字符),第三個分隔符是a,因此將字符串分紅四個部分
'aaa*a*'.split(/(a*)/); // [ '', 'aaa', '*', 'a', '*' ] // 正則表達式使用了括號,第一個組匹配是aaa,第二個組匹配是a,它們都做爲數組成員返回
好比,[abc]
能夠寫成[a-c]
,[0123456789]
能夠寫成[0-9]
,同理[A-Z]
表示26個大寫字母