文章出處

前面的話

  正則表達式在人們的印象中可能是一堆無法理解的字符,但就是這些符號卻實現了字符串的高效操作。通常的情況是,問題本身并不復雜,但沒有正則表達式就成了大問題。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');

  [注意]ES3規范規定,一個正則表達式直接量會在執行到它時轉換為一個RegExp對象,同一段代碼所表示正則表達式直接量的每次運算都返回同一個對象。ES5規范則做了相反的規定,同一段代碼所表示的正則表達式直接量的每次運算都返回新對象。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('q@qq.com'));//true
    console.log(p.test('q@qq'));//false
    console.log(p.test('q@a.qq.com'));//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?[1-9]\d;//10-99
1\d{2};//100-199
2[0-4]\d;//200-249
25[0-5];//250-255
//數字(0-255)
/(00)?\d|0?[1-9]\d|1\d{2}|2[0-4]\d|25[0-5]/;
//ip地址
var ip = /^(((00)?\d|0?[1-9]\d|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章 正則表達式


文章列表


不含病毒。www.avast.com
arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()