正則表達式,也稱規則表達式,常用其來完成對字符串的校驗和過濾。因爲正則表達式的靈活性、邏輯性和功能性都很是強大,並且 能夠利用很簡單的方式完成對複雜字符串的控制,因此不少程序語言都支持正則表達式。在JavaScript
中正則表示也很是強大和實用。javascript
正則表達式(regular expression)是一種表達文本模式(即字符串結構)的方法,有點像字符串的模板,經常用做按照「給定模式」匹配文本的工具。好比,正則表達式給出一個Email地址的模式,而後用它來肯定一個字符串是否爲Email地址。JavaScript的正則表達式體系是參照Perl 5創建的。html
新建正則表達式有兩種方法。一種是使用字面量,以斜槓表示開始和結束。java
// 字面量形式 var telRegex1 = /^1[3|5|7|8]\d{9}$/; // 構造函數形式 var telRegex2 = new RegExp('^1[3|5|7|8]\\d{9}$');
以上都是建立了一個內容爲^1[3|5|7|8]\d{9}$
的正則表達式,其表示對一個手機號碼的校驗。必須以1開始,第二位爲3/5/7/8,以後爲9位數字。es6
這兩種寫法——字面量和構造函數——在運行時有一個細微的區別。採用字面量的寫法,正則對象在代碼載入時(即編譯時)生成;採用構造函數的方法,正則對象在代碼運行時生成。考慮到書寫的便利和直觀,實際應用中,基本上都採用字面量的寫法。web
有一點須要注意,使用構造函數建立正則表達式時,傳入的參數是字符串形式的,在字符串內部,\
自己也是一個轉義符,所以須要再使用一個\
來對其進行正則表達式的轉義。上面第二個示例中,\\d
才能表明任意數字。正則表達式
關於正則表達式中,各類符號的含義,以及使用方法,請看後面的介紹:express
一些經常使用的元字符以下:數組
.
匹配除換行符以外的任意字符jsp
\w
匹配字母或數字或下劃線或漢字函數
\s
匹配任意的空白符
\d
匹配數字
\b
匹配單詞的開始或結束
^
匹配字符串的開始處
$
匹配字符串的結束處。
*
匹配前面的子表達式任意次。
?
匹配前面子表達式0次或一次,等價於{0, 1}
。
+
匹配以前子表達式一次到屢次,等價於{1, }
。
{n}
匹配以前的子表達式n次。
{m,n}
匹配以前的子表達式最少m次,最多n次。
{n, }
匹配以前的子表達式至少n次。
[xyz]
字符集合,表示其中任意一個字符。表示範圍可用-
連接,例如[a-z]
表示a-z之間的任意一個字母。還能夠這樣書寫[A-Za-z0-9]
。
[^xyz]
字符便可,表示非其中任意一個字符。表示範圍可用-
連接,例如[^a-z]
表示非 a-z之間的任意一個字母。
|
表示或(or)
關係,例如 com|cn
,表示匹配com或者cn。
()
用於分組,其分組中的內容可已經過$1-$9
按順序獲取(字符串相關方法中),以後的正則中也能夠經過\1-\9
進行引用(正則表達式內部)。(分組0表示整個正則匹配內容或整個正則表達式)
在正則表達式中,以上這些以及一些未列出的元字符都是有自身含義的,若是咱們須要匹配這些元字符自己,可使用
\
對其進行轉義便可。
更多元字符能夠查看:正則表達式
ignoreCase
:返回一個布爾值,表示是否設置了i修飾符,該屬性只讀。
global
:返回一個布爾值,表示是否設置了g修飾符,該屬性只讀。
multiline
:返回一個布爾值,表示是否設置了m修飾符,該屬性只讀。
sticky
:ES6返回一個布爾值,表示是否設置了y修飾符,只讀。
var r = /abc/igm; r.ignoreCase; // true r.global; // true r.multiline; // true
lastIndex
:返回下一次開始搜索的位置。該屬性可讀寫,可是隻在設置了g修飾符時有意義。
source
:ES5返回正則表達式的字符串形式(不包括反斜槓),該屬性只讀。
flags
:ES6返回正則表達式中的修飾符。
var r = /abc/igm; r.lastIndex; // 0 r.source; // "abc" r.flags; //"igm"
正則對象的test
對象接收一個字符串,表示測試字符串,返回一個布爾值,表示是此字符串是否知足匹配條件。
telRegex1.test('13612341234'); // true telRegex2.test('13612341234'); // true telRegex1.test('136123412'); // false
若是正則表達式帶有g
修飾符,則每一次test
方法都從上一次結束的位置開始向後匹配。同時,能夠經過正則對象的lastIndex
屬性指定開始搜索的位置。
var xReg = /x/g; var str = 'xyz_x1_y1_x3'; xReg.lastIndex; // 0 xReg.test(str); // true xReg.lastIndex; // 1 xReg.test(str); // true xReg.lastIndex; // 5 // 指定位置開始 指定下次匹配從最後一位開始,就匹配不到了 xReg.lastIndex = 11; // 11 xReg.test(str); // false xReg.lastIndex; // 0
var indexReg = /^(?:http|https).+\/jwebui\/pages\/themes\/(\w+)\/\1\.jspx(\?\S+)?$/i ;
上面是一個F8中檢查是否爲首頁的正則表達式。
最開始的^
和最後的$
分別表示匹配的開始和結束。
(?:http|https)
表示二者之一,這麼寫是非獲取的組匹配,()
不會被分組存儲。也能夠寫成(http|https)
可是後面的\1
就須要替換成\2
了,由於這麼寫時此處造成了第一個分組。
.+
就是任意字符至少出現一次。
\/jwebui\/pages\/themes\/
就是匹配字符串"/jwebui/pages/themes/"
。
(\w+)
做爲第一個分組,表示任意字母或數字或下劃線或漢字至少出現一次。
\1
表示對第一個分組的引用,再重複第一分組的內容 。
\.jspx
表示.jspx
。
(\?\S+)?
表示(\?\S+)
匹配的內容出現0次或一次。其中:
\?
表示?
。
\S+
表示任意可見字符出現至少一次。
`
正則對象的exec
方法,能夠返回匹配結果。若是發現匹配,就返回一個數組,成員是每個匹配成功的子字符串,不然返回null
。
若是正則表示式包含圓括號(即含有「組匹配」),則返回的數組會包括多個成員。第一個成員是整個匹配成功的結果,後面的成員就是圓括號對應的匹配成功的組。也就是說,第二個成員對應第一個括號,第三個成員對應第二個括號,以此類推。整個數組的length
屬性等於組匹配的數量再加1。
var ipReg = /(\d{1,3}\.){3}(\d{1,3})/; var ipStr = 'My ip is "192.168.118.47" , please tell me yours'; ipReg.exec(ipStr); // ["192.168.118.47", "118.", "47"]
上面第一段代碼表示一個簡單的IP檢驗,數字的1-3位以後緊跟一個.
,接着這個總體要出現3次,最後再有一段數字的1-3位。結果數組中,第一個值表示匹配到的結果,以後的表示正則分組匹配到的內容。
若是正則表達式加上g修飾符,則可使用屢次exec方法,下一次搜索的位置從上一次匹配成功結束的位置開始。同時還能夠指定lastIndex
,使之下次從指定位置開始(可見以前的test
示例)。
var ipLastReg = /\d+(?=;)/g; var ipsStr = '192.168.118.47;192.168.118.46;192.168.118.48;'; ipLastReg.exec(ipsStr); // ["47"] ipLastReg.exec(ipsStr); // ["46"] ipLastReg.exec(ipsStr); // ["48"]
上面代碼中正則中的(?=;)
表示先行斷言,表示只匹配在;
前面\d+
。
若是隻是爲了獲得是否匹配,請使用
RegExp.test()
方法或字符串實例的.search()
替代,效率更高。
之因此稱之爲字符串相關方法是由於其是在字符串上調用的(雖然ES6開始,內部調用的是正則上的方法,但仍是在字符串上提供的入口)。
match()
:返回一個數組,成員是全部匹配的子字符串。
search()
:按照給定的正則表達式進行搜索,返回一個整數,表示匹配開始的位置。
replace()
:按照給定的正則表達式進行替換,返回替換後的字符串。
split()
:按照給定規則進行字符串分割,返回一個數組,包含分割後的各個成員。
match
方法對字符串進行正則匹配,返回匹配結果。此方法方法與正則對象的exec
方法很是相似:匹配成功返回一個數組,匹配失敗返回null
。若是正則表達式帶有g
修飾符,則該方法與正則對象的exec
方法行爲不一樣,會一次性返回全部匹配成功的結果。
var ipLastReg = /\d+(?=;)/g; var ipsStr = '192.168.118.47;192.168.118.46;192.168.118.48;'; ipsStr.match(ipLastReg); // ["47", "46", "48"]
上面的正則是匹配IP中的最後一位,其中使用了(?=;)
意爲先行斷言,表示只匹配在;
以前的內容,可是不包括;
。關於更多先行斷言,請看下文。
search
方法,返回第一個知足條件的匹配結果(可直接使用字符串,不必定是正則對象)在整個字符串中的位置。若是沒有任何匹配,則返回-1
。
var nowDateStr = '2016-11-1'; var testReg = /-/g; nowDateStr.search(testReg); // 4 // 再次查找仍是4 nowDateStr.search(testReg); // 4 // 檢查lastIndex 並設置 testReg.lastIndex; // 0 testReg.lastIndex = 6; nowDateStr.search(testReg); // 4 結果仍爲4
search
方法老是從字符串的開始位置查找,與正則表達式的g
修飾符和lastIndex
屬性無關。
replace
方法能夠替換匹配的值,返回替換後的新字符串。它接受兩個參數,第一個是搜索模式(可直接使用字符串,不必定是正則對象),第二個是替換的內容(可以使用字符串或一個函數)。搜索模式若是不加g修飾符,就替換第一個匹配成功的值,不然替換全部匹配成功的值。
其中replace
方法的第二個參數可使用美圓符號$,用來指代所替換的內容,具體以下所示:
$&
指代匹配的子字符串。
$`
指代匹配結果前面的文本。
$'
指代匹配結果後面的文本。
$n
指代匹配成功的第n組內容,n是從1開始的天然數。
$$
指代美圓符號$。
var re = /-/g; var str = '2016-11-01'; var newstr = str.replace(re,'.'); console.log(newstr); // "2016.11.01" 'hello world'.replace(/(\w+)\s(\w+)/, '$2 $1'); // "world hello" 'abc'.replace('b', '[$`-$&-$\']'); // "a[a-b-c]c"
第二個參數爲函數:
function toCamelStyle(str) { // 匹配-以及以後的一個字符,其中這個字符在一個分組內 var camelRegExp = /-([a-z])/ig; return str.replace(camelRegExp, function(all, letter) { // all爲匹配到的內容,letter爲組匹配 return letter.toUpperCase(); }); } toCamelStyle('margin-left'); // "marginLeft" toCamelStyle('aa-bb-cccc'); // "aaBbCccc"
以上代碼展現經過正則將aa-bb-cccc
這樣的字符串轉化爲aaBbCccc
這種形式。replace
回調函數接收兩個參數,第一個爲匹配到的內容,第二個爲匹配到的分組,有多少組就能夠傳多少個參數,在此以後還能夠有兩個參數,一個爲匹配到內容在原字符串的位置,另外一個是原字符串。
split
方法按照正則規則分割字符串,返回一個由分割後的各個部分組成的數組。該方法接受兩個參數,第一個參數是分隔規則(可直接使用字符串,不必定是正則對象),第二個參數是返回數組的最大成員數。
'2016-11-01'.split('-'); // ["2016", "11", "01"] '2016-11-01'.split(/-/); // ["2016", "11", "01"]
當正則表達式中包含能接受重複的限定符時,一般的行爲是(在使整個表達式能獲得匹配的前提下)匹配儘量多的字符,稱之爲貪婪模式。
例如:
var s = 'aaa'; s.match(/a+/); // ["aaa"]
有時,咱們更須要懶惰匹配,也就是匹配儘量少的字符。前面給出的限定符均可以被轉化爲懶惰匹配模式,只要在它後面加上一個問號?。這樣.*?就意味着匹配任意數量的重複,可是在能使整個匹配成功的前提下使用最少的重複。
var s = 'aaa'; s.match(/a+?/); // ["a"]
如下是一些說明
*?
重複任意次,但儘量少重複
+?
重複1次或更屢次,但儘量少重複
??
重複0次或1次,但儘量少重複
{n,m}?
重複n到m次,但儘量少重複
{n,}?
重複n次以上,但儘量少重複
也就是說默認狀況下,都是貪婪模式,加上一個?
時就轉化爲了懶惰模式,也稱非貪婪模式。
一般一個()
中的內容就構成了一個分組,此分組內容將被存儲,可在以後的正則表達式(使用\1-\9
)和相關方法中(使用 $1-$9
)引用,前面已經介紹過了,就再也不說了。
關於組匹配,還有如下幾種狀況:
(?:x)
稱爲非捕獲組(Non-capturing group),表示不返回該組匹配的內容,即匹配的結果中不計入這個括號。
// 正常匹配 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)
稱爲先行斷言(Positive look-ahead),x
只有在y
前面才匹配,y
不會被計入返回結果。
好比以前匹配ip的例子:
var ipLastReg = /\d+(?=;)/g; var ipsStr = '192.168.118.47;192.168.118.46;192.168.118.48;'; ipsStr.match(ipLastReg); // ["47", "46", "48"]
上面正則對象中(?=;)
就表示只匹配在;
以前的內容,可是不包括;
。
x(?!y)
稱爲先行否認斷言(Negative look-ahead),x
只有不在y
前面才匹配,y
不會被計入返回結果。
var xreg = /\d+(?!%)/g ; xreg.exec('100% is 1'); // ["10"] xreg.exec('100% is 1'); // ["1"] /\d+?(?!%)/.exec('100% is 1'); // ["1"]
上面代碼表示匹配不在%
前的數字,xreg
中直接書寫的\d+
表示貪婪模式,所以第一次匹配到的是10,第二次纔會匹配到後面的1,由於做爲數字10自己也不在%
前面,正則不會將100當成一個總體(注意:這裏須要定義一個正則對象來調用,直接以字面量形式的正則調用時,每次調用都是一個新對象,結果始終是10
)。
爲了一次匹配到最後的1
,咱們在\d+
以後加一個?
將其轉爲非貪婪模式便可。
爲了一次匹配到前面100
中的1
,咱們在\d+
以後加一個?
將其轉爲非貪婪模式便可。
ES6以前,
JavaScript
中不支持後行斷言和否認後行斷言,ES6中添加了對此的支持,請看以後的ES擴展部分。
RegExp構造函數的參數有兩種狀況。
第一種狀況是,參數是字符串,這時第二個參數表示正則表達式的修飾符(flag)。
第二種狀況是,參數是一個正則表示式,此時不能有第二個參數,會返回一個原有正則表達式的拷貝。
ES6 針對第二種狀況,容許傳入第二個參數,用於設置第一個參數正則表達式的修飾符。
var regex = new RegExp(/xyz/, 'i'); // ES6以前 語法錯誤 new RegExp(/abc/ig, 'i'); // ES6中結果爲: /abc/i
字符串對象共有4個方法,可使用正則表達式:match()
、replace()
、search()
和split()
。
ES6將這4個方法,在語言內部所有調用RegExp
的實例方法,從而作到全部與正則相關的方法,全都定義在RegExp對象上。
ES6對正則表達式添加了u
修飾符,含義爲「Unicode
模式」,用來正確處理大於uFFFF的Unicode字符。也就是說,會正確處理四個字節的UTF-16編碼。
ES6還爲正則表達式添加了y
修飾符,叫作「粘連」(sticky
)修飾符。
y
修飾符的做用與g
修飾符相似,也是全局匹配,後一次匹配都從上一次匹配成功的下一個位置開始。不一樣之處在於,g
修飾符只要剩餘位置中存在匹配就可,而y修飾符確保匹配必須從剩餘的第一個位置開始,這也就是「粘連」的涵義。
var s = 'aaa_aa_a'; var r1 = /a+/g; var r2 = /a+/y; // 第一次都能正確匹配 r1.exec(s); // ["aaa"] r2.exec(s); // ["aaa"] // 第二次結果就不一致了 r1.exec(s); // ["aa"] r2.exec(s); // null
我的理解,\y
是相似於在每次匹配時隱式地添加了^
,表示開始位置。
ES5中,正則對象存在source
屬性,用於返回正則表達式自己。
ES6中,又添加了flags
屬性,用於返回正則對象的全部修飾符。
後行斷言於先行斷言相反。例如/(?<=y)x/
表示匹配x
,可是要求x
必須在y
後面。
同理 後行否認斷言則爲:/(?<!=y)x/
表示匹配x
,可是要求x
不能在y
後面。
須要注意的是,存在後行斷言時,正則執行順序發生了改變,會先匹配後行斷言的這部分,再匹配其餘的的,順序變成了從右向左。所以一些匹配操做的結果可能大不一致,並且正則中的
\1-\9
的引用順序也會發生變化。
原文發表在個人博客JavaScript正則表達式RegExp,歡迎訪問!
先行否認斷言中
爲了一次匹配到最後的1
,咱們在\d+
以後加一個?
將其轉爲非貪婪模式便可。
爲了一次匹配到前面100
中的1
,咱們在\d+
以後加一個?
將其轉爲非貪婪模式便可。