[1]定義 [2]特點 [3]元字元 [4]轉義字元 [5]字元組 [6]量詞 [7]括弧 [8]選擇 [9]斷言 [10]匹配模式 [11]優先順序 [12]局限性 ...
×
目錄
[1]定義 [2]特點 [3]元字元[4]轉義字元[5]字元組[6]量詞[7]括弧[8]選擇[9]斷言[10]模式[11]優先順序[12]局限性前面的話
正則表達式在人們的印象中可能是一堆無法理解的字元,但就是這些符號卻實現了字元串的高效操作。通常的情況是,問題本身並不複雜,但沒有正則表達式就成了大問題。javascript中的正則表達式作為相當重要的知識,本文將介紹正則表達式的基礎語法
定義
正則表達式(Regular Expression)是一門簡單語言的語法規範,是強大、便捷、高效的文本處理工具,它應用在一些方法中,對字元串中的信息實現查找、替換和提取操作
javascript中的正則表達式用RegExp對象表示,有兩種寫法:一種是字面量寫法;另一種是構造函數寫法
Perl寫法
正則表達式字面量寫法,又叫Perl寫法,因為javascript的正則表達式特性借鑒自Perl
正則表達式字面量定義為包含在一對斜杠(/)之間的字元,並且可以設置3個標誌
var expression = /pattern/flags;
正則表達式的匹配模式支持下列3個標誌:
g:表示全局(global)模式,即模式將被應用於所有字元串,而非在發現第一個匹配項時立即停止
i:表示不區分大小寫(case-insensitive)模式,即在確定匹配項時忽略模式與字元串的大小寫
m:表示多行(multiline)模式,即在到達一行文本末尾時還會繼續查找下一行中是否存在與模式匹配的項
//匹配字元串所有'at'的實例 var p = /at/g; //test()方法返回一個布爾值表示是否可以找到匹配項 console.log(p.test('ata'));//true console.log(p.test('aba'));//false
RegExp構造函數
和普通的內置對象一樣,RegExp正則表達式對象也支持new+RegExp()構造函數的形式
RegExp構造函數接收兩個參數:要匹配的字元串模式(pattern)和可選的標誌字元串(flags),標誌字元串和字面量的三個標誌含義相同:'g'、'i'、'm'
RegExp構造函數的兩個參數都是字元串。且使用字面量形式定義的任何表達式都可使用構造函數
//匹配字元串所有'at'的實例 var p1 = /at/g; //同上 var p2 = new RegExp('at','g');
[註意]ECMAScript3規範規定,一個正則表達式直接量會在執行到它時轉換為一個RegExp對象,同一段代碼所表示正則表達式直接量的每次運算都返回同一個對象。ECMAScript5規範則做了相反的規定,同一段代碼所表示的正則表達式直接量的每次運算都返回新對象。IE6-8一直是按照ECMAScript5規範的方式實現的,所以並沒有相容性問題
特點
javascript中的正則表達式最大的特點是不支持空白,必須寫在一行中
//匹配ab console.log(/ab/.test('ab')); //true console.log(/ ab/.test('ab')); //false console.log(/a b/.test('ab')); //false console.log(/ab /.test('ab')); //false
元字元
大部分字元在正則表達式中,就是字面的含義,比如/a/匹配a,/b/匹配b
/dog/.test("old dog") // true
但還有一些字元,它們除了字面意思外,還有著特殊的含義,這些字元就是元字元
在javascript中,共有14個元字元(meta-character)
() [] {} \ ^ $ | ? * + .
元字元 名稱 匹配對象 . 點號 單個任意字元(除回車\r、換行\n、行分隔符\u2028和段分隔符\u2029外) [] 字元組 列出的單個任意字元 [^] 排除型字元組 未列出的單個任意字元 ? 問號 匹配0次或1次 * 星號 匹配0交或多次 + 加號 匹配1次或多次 {min,max} 區間量詞 匹配至少min次,最多max次 ^ 脫字元 行的起始位置 $ 美元符 行的結束位置 | 豎線 分隔兩邊的任意一個表達式 () 括弧 限制多選結構的範圍,標註量詞作用的元素,為反向引用捕獲文本 \1,\2... 反向引用 匹配之前的第一、第二...組括弧內的表達式匹配的文本
轉義字元
轉義字元(escape)表示為反斜線(\)+字元的形式,共有以下3種情況
【1】因為元字元有特殊的含義,所以無法直接匹配。如果要匹配它們本身,則需要在它們前面加上反斜杠(\)
console.log(/1+1/.test('1+1')); //false console.log(/1\+1/.test('1+1')); //true console.log(/\*/.test('*')); //true console.log(/*/.test('*')); //報錯
但實際上,並非14個元字元都需要轉義,右方括弧]和右花括弧}不需要轉義
console.log(/]/.test(']')); //true console.log(/\]/.test(']')); //true console.log(/\}/.test('}')); //true console.log(/}/.test('}')); //true
【2】'\'加非元字元,表示一些不能列印的特殊字元
\0 NUL字元\u0000 [\b] 匹配退格符\u0008,不要與\b混淆 \t 製表符\u0009 \n 換行符\u000A \v 垂直製表符\u000B \f 換頁符\u000C \r 回車符\u000D \xnn 由十六進位數nn指定的拉丁字元 \uxxxx 由十六進位數xxxx指定的Unicode字元(\u4e00-\u9fa5代表中文) \cX 控制字元^X,表示ctrl-[X],其中的X是A-Z之中任一個英文字母,用來匹配控制字元
【3】'\'加任意其他字元,預設情況就是匹配此字元,也就是說,反斜線(\)被忽略了
console.log(/\x/.test('x')); //true console.log(/\y/.test('y')); //true console.log(/\z/.test('z')); //true
雙重轉義
由於RegExp構造函數的參數是字元串,所以某些情況下,需要對字元進行雙重轉義
字元\在正則表達式字元串中通常被轉義為\\
var p1 = /\.at/; //等價於 var p2 = new RegExp('\\.at'); var p1 = /name\/age/; //等價於 var p2 = new RegExp('name\\/age'); var p1 = /\w\\hello\\123/; //等價於 var p2 = new RegExp('\\w\\\\hello\\\\123');
字元組
字元組(Character Class),有的編譯成字元類或字元集。簡單而言,就是指用方括弧表示的一組字元,它匹配若幹字元之一
//匹配0-9這10個數字之一 var p = /[0123456789]/; p.test('1');//true p.test('a');//false
[註意]字元組中的字元排列順序並不影響字元組的功能,出現重覆字元也不會影響
/[0123456789]/ //等價於 /[9876543210]/ //等價於 /[1234567890123456789]/
範圍
正則表達式通過連字元(-)提供了範圍表示法,可以簡化字元組
/[0123456789]/ //等價於 /[0-9]/
/[abcdefghijklmnopqrstuvwxyz]/ //等價於 /[a-z]/
連字元(-)表示的範圍是根據ASCII編碼的碼值來確定的,碼值小的在前,碼值大的在後
所以[0-9]是合法的,而[9-0]會報錯
//匹配0-9這10個數字之一 var p1 = /[0-9]/; p1.test('1');//true var p2 = /[9-0]/;//報錯 p2.test('1');
在字元組中可以同時併列多個'-'範圍
/[0-9a-zA-Z]/;//匹配數字、大寫字母和小寫字母 /[0-9a-fA-F]/;//匹配數字,大、小寫形式的a-f,用來驗證十六進位字元 console.log(/[0-9a-fA-F]/.test('d'));//true console.log(/[0-9a-fA-F]/.test('x'));//false
只有在字元組內部,連字元'-'才是元字元,表示一個範圍,否則它就只能匹配普通的連字元號
[註意]如果連字元出現在字元組的開頭或末尾,它表示的也是普通的連字元號,而不是一個範圍
//匹配中劃線 console.log(/-/.test('-'));//true console.log(/[-]/.test('-'));//true //匹配0-9的數字或中劃線 console.log(/[0-9]/.test('-'));//false console.log(/[0-9-]/.test('-'));//true console.log(/[0-9\-]/.test('-'));//true console.log(/[-0-9]/.test('-'));//true console.log(/[\-0-9]/.test('-'));//true
排除
字元組的另一個類型是排除型字元組,在左方括弧後緊跟一個脫字元'^'表示,表示在當前位置匹配一個沒有列出的字元
所以[^0-9]表示0-9以外的字元
//匹配第一個是數字字元,第二個不是數字字元的字元串 console.log(/[0-9][^0-9]/.test('1e'));//true console.log(/[0-9][^0-9]/.test('q2'));//false
[註意]在字元組內部,脫字元'^'表示排除,而在字元組外部,脫字元'^'表示一個行錨點
^符號是元字元,在字元組中只要^符號不挨著左方括弧就可以表示其本身含義,不轉義也可以
//匹配abc和^符號 console.log(/[a-c^]/.test('^'));//true console.log(/[a-c\^]/.test('^'));//true console.log(/[\^a-c]/.test('^'));//true
在字元組中,只有^、-、[、]這4個字元可能被當做元字元,其他有元字元功能的字元都只表示其本身
console.log(/[[1]]/.test('['));//false console.log(/[[1]]/.test(']'));//false console.log(/[\1]/.test('\\'));//false console.log(/[^^]/.test('^'));//false console.log(/[1-2]/.test('-'));//false console.log(/[\[1\]]/.test('['));//true console.log(/[\[1\]]/.test(']'));//true console.log(/[\\]/.test('\\'));//true console.log(/[^]/.test('^'));//true console.log(/[1-2\-]/.test('-'));//true
console.log(/[(1)]/.test('('));//true console.log(/[(1)]/.test(')'));//true console.log(/[{1}]/.test('{'));//true console.log(/[{1}]/.test('}'));//true console.log(/[1$]/.test('$'));//true console.log(/[1|2]/.test('|'));//true console.log(/[1?]/.test('?'));//true console.log(/[1*]/.test('*'));//true console.log(/[1+]/.test('+'));//true console.log(/[1.]/.test('.'));//true
簡記
用[0-9]、[a-z]等字元組,可以很方便地表示數字字元和小寫字母字元。對於這類常用字元組,正則表達式提供了更簡單的記法,這就是字元組簡記(shorthands)
常見的字元組簡記有\d、\w、\s。其中d表示(digit)數字,w表示(word)單詞,s表示(space)空白
正則表達式也提供了對應排除型字元組的簡記法:\D、\W、\S。字母完全相同,只是改為大寫,這些簡記法匹配的字元互補
\d 數字,等同於[0-9] \D 非數字,等同於[^0-9] \s 空白字元,等同於[\f\n\r\t\u000B\u0020\u00A0\u2028\u2029] \S 非空白字元,等同於[^\f\n\r\t\u000B\u0020\u00A0\u2028\u2029] \w 字母、數字、下劃線,等同於[0-9A-Za-z_](漢字不屬於\w) \W 非字母、數字、下劃線,等同於[^0-9A-Za-z_]
[註意]\w不僅包括字母、數字,還包括下劃線。在進行數字驗證時,只允許輸入字母和數字時,不可以使用\w,而應該使用[0-9a-zA-Z]
任意字元
人們一般認為點號可以代表任意字元,其實並不是
.點號代表除回車(\r)、換行(\n) 、行分隔符(\u2028)和段分隔符(\u2029)以外的任意字元
妥善的利用互補屬性,可以得到一些巧妙的效果。比如,[\s\S]、[\w\W]、[\d\D]都可以表示任意字元
//匹配任意字元 console.log(/./.test('\r'));//false console.log(/[\s\S]/.test('\r'));//true
量詞
根據字元組的介紹,可以用字元組[0-9]或\d來匹配單個數字字元,如果用正則表達式表示更複雜的字元串,則不太方便
//表示郵政編碼6位數字 /[0-9][0-9][0-9][0-9][0-9][0-9]/; //等價於 /\d\d\d\d\d\d/;
正則表達式提供了量詞,用來設定某個模式出現的次數
{n} 匹配n次 {n,m} 匹配至少n次,最多m次 {n,} 匹配至少n次 ? 相當於{0,1} * 相當於{0,} + 相當於{1,}
//表示郵政編碼6位數字 /\d{6}/;
美國英語和英國英語有些詞的寫法不一樣,如果traveler和traveller,favor和favour,color和colour
//同時匹配美國英語和英國英語單詞 /travell?er/; /favou?r/; /colou?r/;
協議名有http和https兩種
/https?/;
量詞廣泛應用於解析HTML代碼。HTML是一種標簽語言,它包含各種各樣的標簽,比如<head>、<img>、<table>。它們都是從<開始,到>結束,而標簽名的長度不同
console.log(/<[^<>]+>/.test('<head>'));//true console.log(/<[^<>]+>/.test('<img>'));//true console.log(/<[^<>]+>/.test('<>'));//false
HTML標簽不能為空標簽,而引號字元串的兩個引號之間可以為0個字元
console.log(/'[^']*'/.test("''"));//true console.log(/'[^']*'/.test("'abc'"));//true
貪婪模式
預設情況下,量詞都是貪婪模式(greedy quantifier),即匹配到下一個字元不滿足匹配規則為止
//exec()方法以數組的形式返回匹配結果 /a+/.exec('aaa'); // ['aaa']
懶惰模式
懶惰模式(lazy quantifier)和貪婪模式相對應,在量詞後加問號'?'表示,表示儘可能少的匹配,一旦條件滿足就不往下匹配
{n}? 匹配n次 {n,m}? 匹配至少n次,最多m次 {n,}? 匹配至少n次 ?? 相當於{0,1} *? 相當於{0,} +? 相當於{1,}
/a+?/.exec('aaa'); // ['a']
匹配<script></script>之間的代碼看上去很容易
/<script>[\s\S]*<\/script>/
//["<script>alert("1");</script>"] /<script>[\s\S]*<\/script>/.exec('<script>alert("1");</script>');
但如果多次出現script標簽,就會出問題
//["<script>alert("1");</script><br><script>alert("2");</script>"] /<script>[\s\S]*<\/script>/.exec('<script>alert("1");</script><br><script>alert("2");</script>');
它把無用的<br>標簽也匹配出來了,此時就需要使用懶惰模式
//["<script>alert("1");</script>"] /<script>[\s\S]*?<\/script>/.exec('<script>alert("1");</script><br><script>alert("2");</script>');
在javascript中,/* */是註釋的一種形式,在文檔中可能出現多次,這時就必須使用懶惰模式
/\/\*[\s\S]*?\*\//
//["/*abc*/"] /\/\*[\s\S]*?\*\//.exec('/*abc*/<br>/*123*/');
括弧
括弧有兩個功能,分別是分組和引用。具體而言,是用於限定量詞或選擇項的作用範圍,用於捕獲文本並可以進行引用或反向引用
分組
量詞控制之前元素的出現次數,而這個元素可能是一個字元,也可能是一個字元組,也可以是一個表達式
如果把一個表達式用括弧包圍起來,這個元素就是括弧里的表達式,被稱為子表達式
如果希望字元串'ab'重覆出現2次,應該寫為(ab){2},而如果寫為ab{2},則{2}只限定b
console.log(/(ab){2}/.test('abab'));//true console.log(/(ab){2}/.test('abb'));//false console.log(/ab{2}/.test('abab'));//false console.log(/ab{2}/.test('abb'));//true
身份證長度有15位和18位兩種,如果只匹配長度,可能會想當然地寫成\d{15,18},實際上這是錯誤的,因為它包括15、16、17、18這四種長度。因此,正確的寫法應該是\d{15}(\d{3})?
email地址以@分隔成兩段,之前的部分是用戶名,之後的部分是主機名
用戶名允許出現數字、字母和下劃線,長度一般在1-64個字元之間,則正則可表示為/\w{1,64}/
主機名一般表現為a.b.···.c,其中c為主功能變數名稱,其他為級數不定的子功能變數名稱,則正則可表示為/([-a-zA-z0-9]{1,63}\.)+[-a-zA-Z0-9]{1,63}/
所以email地址的正則表達式如下:
var p =/\w{1,64}@([-a-zA-z0-9]{1,63}\.)+[-a-zA-Z0-9]{1,63}/; console.log(p.test('[email protected]'));//true console.log(p.test('q@qq'));//false console.log(p.test('[email protected]'));//true
捕獲
括弧不僅可以對元素進行分組,還會保存每個分組匹配的文本,等到匹配完成後,引用捕獲的內容。因為捕獲了文本,這種功能叫捕獲分組
比如,要匹配諸如2016-06-23這樣的日期字元串
/(\d{4})-(\d{2})-(\d{2})/
與以往不同的是,年、月、日這三個數值被括弧括起來了,從左到右為第1個括弧、第2個括弧和第3個括弧,分別代表第1、2、3個捕獲組
javascript有9個用於存儲捕獲組的構造函數屬性
RegExp.$1\RegExp.$2\RegExp.$3……到RegExp.$9分別用於存儲第一、第二……第九個匹配的捕獲組。在調用exec()或test()方法時,這些屬性會被自動填充
console.log(/(\d{4})-(\d{2})-(\d{2})/.test('2016-06-23'));//true console.log(RegExp.$1);//'2016' console.log(RegExp.$2);//'06' console.log(RegExp.$3);//'23' console.log(RegExp.$4);//''
而exec()方法是專門為捕獲組而設計的,返回的數組中,第一項是與整個模式匹配的字元串,其他項是與模式中的捕獲組匹配的字元串
console.log(/(\d{4})-(\d{2})-(\d{2})/.exec('2016-06-23'));//["2016-06-23", "2016", "06", "23"]
捕獲分組捕獲的文本,不僅可以用於數據提取,也可以用於替換
replace()方法就是用於進行數據替換的,該方法接收兩個參數,第一個參數為待查找的內容,而第二個參數為替換的內容
console.log('2000-01-01'.replace(/-/g,'.'));//2000.01.01
在replace()方法中也可以引用分組,形式是$num,num是對應分組的編號
//把2000-01-01的形式變成01-01-2000的形式 console.log('2000-01-01'.replace(/(\d{4})-(\d{2})-(\d{2})/g,'$3-$2-$1'));//'01-01-2000'
反向引用
英文中不少單詞都有重疊出現的字母,如shoot或beep。若想檢查某個單詞是否包含重疊出現的字母,則需要引入反向引用(back-reference)
反向引用允許在正則表達式內部引用之前捕獲分組匹配的文本,形式是\num,num表示所引用分組的編號
//重覆字母 /([a-z])\1/ console.log(/([a-z])\1/.test('aa'));//true console.log(/([a-z])\1/.test('ab'));//false
反向引用可以用於建立前後聯繫。HTML標簽的開始標簽和結束標簽是對應的
//開始標簽 <([^>]+)> //標簽內容 [\s\S]*? //匹配成對的標簽 /<([^>]+)>[\s\S]*?<\/\1>/ console.log(/<([^>]+)>[\s\S]*?<\/\1>/.test('<a>123</a>'));//true console.log(/<([^>]+)>[\s\S]*?<\/\1>/.test('<a>123</b>'));//false
非捕獲
除了捕獲分組,正則表達式還提供了非捕獲分組(non-capturing group),以(?:)的形式表示,它只用於限定作用範圍,而不捕獲任何文本
比如,要匹配abcabc這個字元,一般地,可以寫為(abc){2},但由於並不需要捕獲文本,只是限定了量詞的作用範圍,所以應該寫為(?:abc){2}
console.log(/(abc){2}/.test('abcabc'));//true console.log(/(?:abc){2}/.test('abcabc'));//true
由於非捕獲分組不捕獲文本,對應地,也就沒有捕獲組編號
console.log(/(abc){2}/.test('abcabc'));//true console.log(RegExp.$1);//'abc' console.log(/(?:abc){2}/.test('abcabc'));//true console.log(RegExp.$1);//''
非捕獲分組也不可以使用反向引用
/(?:123)\1/.test('123123');//false /(123)\1/.test('123123');//true
捕獲分組和非捕獲分組可以在一個正則表達式中同時出現
console.log(/(\d)(\d)(?:\d)(\d)(\d)/.exec('12345'));//["12345", "1", "2", "4", "5"]
選擇
豎線'|'在正則表達式中表示或(OR)關係的選擇,以豎線'|'分隔開的多個子表達式也叫選擇分支或選擇項。在一個選擇結構中,選擇分支的數目沒有限制
在選擇結構中,豎線|用來分隔選擇項,而括弧()用來規定整個選擇結構的範圍。如果沒有出現括弧,則將整個表達式視為一個選擇結構
選擇項的嘗試匹配次序是從左到右,直到發現了匹配項,如果某個選擇項匹配就忽略右側其他選擇項,如果所有子選擇項都不匹配,則整個選擇結構匹配失敗
console.log(/12|23|34/.exec('1'));//null console.log(/12|23|34/.exec('12'));//['12'] console.log(/12|23|34/.exec('23'));//['23'] console.log(/12|23|34/.exec('2334'));//['23']
ip地址一般由3個點號和4段數字組成,每段數字都在0-255之間
(00)?\d; //0-9 0?\d{2};//10-99 1\d{2};//100-199 2[0-4]\d;//200-249 25[0-5];//250-255 //數字(0-255) /(00)?\d|0?\d{2}|1\d{2}|2[0-4]\d|25[0-5]/;
//ip地址 var ip = /^(((00)?\d|0?\d{2}|1\d{2}|2[0-4]\d|25[0-5])\.){3}\2$/; console.log(ip.test('1.1.1.1'));//true console.log(ip.test('1.1.1'));//false console.log(ip.test('256.1.1.1'));//false
類似地,時間匹配也需要分段處理
//月(1-12) 0?\d|1[0-2] //日(1-31) 0?\d|[12]\d|3[01] //小時(0-24) 0?\d|1\d|2[0-4] //分鐘(0-60) 0?\d|[1-5]\d|60
手機號一般是11位,前3位是號段,後8位一般沒有限制。而且,在手機開頭很可能有0或+86
//開頭 (0|\+86)? //前3位 13\d|14[579]|15[0-35-9]|17[0135-8]|18\d //後8位 \d{8} //手機號碼 var phone = /(0|\+86)?(13\d|14[579]|15[0-35-9]|17[0135-8]|18\d)\d{8}/; console.log(phone.test('13453250661'));//true console.log(phone.test('1913250661'));//false console.log(phone.test('1345325061'));//false
在選擇結構中,應該儘量避免選擇分支中存在重覆匹配,因為這樣會大大增加回溯的計算量
//不良的選擇結構 a|[ab] [0-9]|\w
斷言
在正則表達式中,有些結構並不真正匹配文本,而只負責判斷在某個位置左/右側是否符合要求,這種結構被稱為斷言(assertion),也稱為錨點(anchor),常見的斷言有3種:單詞邊界、行開頭結尾、環視
單詞邊界
在文本處理中經常可能進行單詞替換,比如把row替換成line。但是,如果直接替換,不僅所有單詞row都被替換成line,單詞內部的row也會被替換成line。要想解決這個問題,必須有辦法確定單詞row,而不是字元串row
為瞭解決這類問題,正則表達式提供了專用的單詞邊界(word boundary),記為\b,它匹配的是'單詞邊界'位置,而不是字元。\b匹配的是一邊是單詞字元\w,一邊是非單詞字元\W的位置
與\b對應的還有\B,表示非單詞邊界,但實際上\B很少使用
console.log(/\ban\b/.test('an apple'));//true console.log(/\ban\b/.test('a an'));//true console.log(/\ban\b/.test('an'));//true console.log(/\ban\b/.test('and'));//false console.log(/\ban\b/.test('ban'));//false
起始結束
常見的斷言還有^和$,它們分別匹配字元串的開始位置和結束位置,所以可以用來判斷整個字元串能否由表達式匹配
//匹配第一個單詞 console.log(/^\w*/.exec('first word\nsecond word\nthird word'));//['first'] //匹配最後一個單詞 console.log(/\w*$/.exec('first word\nsecond word\nthird word'));//['word']
console.log(/^a$/.test('a\n'));//false console.log(/^a$/.test('a'));//true
^和$的常用功能是刪除字元串首尾多餘的空白,類似於字元串String對象的trim()方法
function fnTrim(str){ return str.replace(/^\s+|\s+$/,'') } console.log(fnTrim(' hello world '));//'hello world'
環視
環視(look-around),可形象地解釋為停上原地,四處張望。環視類似於單詞邊界,在它旁邊的文本需要滿足某種條件,而且本身不匹配任何字元
環視分為正序環視和逆序環視,而javascript只支持正序環視,相當於只支持向前看,不支持往回看
而正序環視又分為肯定正序環視和否定正序環視
肯定正序環視的記法是(?=n),表示前面必須是n才匹配;否定正序環視的記憶法是(?!n),表示前面必須不是n才匹配
console.log(/a(?=b)/.exec('abc'));//['a'] console.log(/a(?=b)/.exec('ac'));//null console.log(/a(?!b)/.exec('abc'));//null console.log(/a(?!b)/.exec('ac'));//['a'] console.log(/a(?=b)b/.exec('abc'));//['ab']
[註意]環視雖然也用到括弧,卻與捕獲型分組編號無關;但如果環視結構出現捕獲型括弧,則會影響分組
console.log(/ab(?=cd)/.exec('abcd'));['ab']
console.log(/ab(?=(cd))/.exec('abcd'));['ab','cd']
匹配模式
匹配模式(match mode)指匹配時的使用的規則。設置特定的模式,可能會改變對正則表達式的識別。前面已經介紹過創建正則表達式對象時,可以設置'm'、'i'、'g'這三個標誌,分別對應多行模式、不區分大小模式和全局模式三種
i
預設地,正則表達式是區分大小寫的,通過設置標誌'i',可以忽略大小寫(ignore case)
console.log(/ab/.test('aB'));//false console.log(/ab/i.test('aB'));//true
m
預設地,正則表達式中的^和$匹配的是整個字元串的起始位置和結束位置,而通過設置標誌'm',開啟多行模式,它們也能匹配字元串內部某一行文本的起始位置和結束位置
console.log(/world$/.test('hello world\n')); //false console.log(/world$/m.test('hello world\n')); //true console.log(/^b/.test('a\nb')); //false console.log(/^b/m.test('a\nb')); //true
g
預設地,第一次匹配成功後,正則對象就停止向下匹配了。g修飾符表示全局匹配(global),設置'g'標誌後,正則對象將匹配全部符合條件的結果,主要用於搜索和替換
console.log('1a,2a,3a'.replace(/a/,'b'));//'1b,2a,3a' console.log('1a,2a,3a'.replace(/a/g,'b'));//'1b,2b,3b'
優先順序
正則表達式千變萬化,都是由之前介紹過的字元組、括弧、量詞等基本結構組合而成的
//從上到下,優先順序逐漸降低 \ 轉義符 () (?!) (?=) [] 括弧、字元組、環視 * + ? {n} {n,} {n,m} 量詞 ^ $ 起始結束位置 | 選擇
由於括弧的用途之一就是為量詞限定作用範圍,所以優先順序比量詞高
console.log(/ab{2}/.test('abab'));//false console.log(/(ab){2}/.test('abab'));//true
[註意]選擇符'|'的優先順序最低,比起始和結束位置都要低
console.log(/^ab|cd$/.test('abc'));//true console.log(/^(ab|cd)$/.test('abc'));//false
局限性
儘管javascript中的正則表達式功能比較完備,但與其他語言相比,缺少某些特性
下麵列出了javascript正則表達式不支持的特性
【1】POSIX字元組(只支持普通字元組和排除型字元組)
【2】Unicode支持(只支持單個Unicode字元)
【3】匹配字元串開始和結尾的\A和\Z錨(只支持^和$)
【4】逆序環視(只支持順序環視)
【5】命名分組(只支持0-9編號的捕獲組)
【6】單行模式和註釋模式(只支持m、i、g)
【7】模式作用範圍
【8】純文本模式
參考資料
【1】 阮一峰Javascript標準參考教程——標準庫RegExp對象 http://javascript.ruanyifeng.com/stdlib/regexp.html
【2】《正則指引》
【3】《精通正則表達式》
【4】《javascript權威指南(第6版)》第10章 正則表達式的模式匹配
【5】《javascript高級程式設計(第3版)》第5章 引用類型
【6】《javascript語言精粹(修訂版)》第7章 正則表達式