簡介
正則表達式,又稱正規表示法、正規表達式、規則表達式、常規表示法(英語:Regular Expression,在代碼中常簡寫為regex、regexp或RE),計算機科學的一個概念。正則表達式使用單個字符串來描述、匹配一系列符合某個句法規則的字符串。在很多文本編輯器里,正則表達式通常被用來檢索、替換那些符合某個模式的文本。
說人話就是:對字符串執行模式匹配的強大工具。
Javascript中的正則表達式相較于其他語言來說實現的并不完整,但仍然是十分強大的,能夠幫助我們完成絕大多數模式匹配任務。
定義
在javascript中,正則表達式的定義和數組以及對象的定義一樣有倆種方式。 一種是直接量,另一種是構造函數。
直接量
Javascript可以使用類似Perl的語法定義一個正則表達式
var r = /pattern/flags;
其中pattern是任何簡單或復雜的正則表達式,flags是用以表達正則表達式行為的一個或者多個標識。
flags
- g 表示全局(global)模式,即模式將被應用于所有字符串
- i 表示不區分大小寫
- m 多行模式
舉個栗子:
var reg1 = /ip/g; // 匹配字符串中所有'ip'的實例
var reg2 = /com/gi; // 匹配以'com'結尾的三個字符的組合,不區分大小寫
使用構造函數
Javascript中正則表達式的構造函數為RegExp,即Regular Expression的縮寫,它接收兩個參數,第一個為要匹配的字符串模式,另一個是可選的標識位。
var reg = new RegExp('nice', 'g'); // 匹配字符串中所有的'nice'
注意:第一個參數是一個字符串nice
,而不是正則表達式的直接量/nice/
。
雙重轉義
所有元字符都需要進行雙重轉義
所有元字符都需要進行雙重轉義
所有元字符都需要進行雙重轉義
使用構造函數
定義正則表達式,由于構造函數的第一個參數必須是一個字符串,在匹配元字符時,需要雙重轉義。
// 匹配{user}
var reg1 = new RegExp('\{user\}', 'g'); // wrong
// 由于\在字符串中需要轉義為\\,所以,如果要匹配{user},正則表達式需要寫為
var reg1 = new RegExp('\\{user\\}', 'g');
基本概念總結
元字符
在正則表達式的模式中,有一些字符是有特殊含義的,被稱為元字符,如果要匹配元字符,則必須對其進行轉義,如果用構造函數,則要進行雙重轉義。
這些元字符分別是(一共14個):
{ ( [ \ ^ $ | ? * + . ] ) }
直接量字符
字符 | 匹配 |
---|---|
字母數字字符 | 自身 |
\0 | 查找 NUL 字符。 |
\n | 查找換行符。 |
\f | 查找換頁符。 |
\r | 查找回車符。 |
\t | 查找制表符。 |
\v | 查找垂直制表符。 |
\xxx | 查找以八進制數 xxx 規定的字符。 |
\xdd | 查找以十六進制數 dd 規定的字符。 |
\uxxxx | 查找以十六進制數 xxxx 規定的 Unicode 字符。 |
不管一個直接量字符字符代表何種含義,單個字符始終只匹配單個字符
字符類
字符 | 等價于 | 匹配 |
---|---|---|
. | [^\n\r] | 查找單個字符,除了換行和行結束符。 |
\w | [a-zA-Z_0-9] | 任意ASCII單字字符,等價于[a-zA-Z0-9_] |
\W | [^a-zA-Z_0-9] | 查找非單詞字符。 |
\d | [0-9] | 查找數字。 |
\D | [^0-9] | 查找非數字字符。 |
\s | [ \t\n\x0B\f\r] | 查找空白字符。 |
\S | [^ \t\n\x0B\f\r] | 查找非空白字符。 |
[] | 來表示單個字符有或的關系,如/[bc]/,匹配b或者c | |
^ | 來表示不匹配后面跟著的字符,如/[^bc],/不匹配b或c | |
- | 來表示一個范圍,如/[a-z]/,匹配a-z的字母,可以和負向類結合/^0-9/ | |
組合類: | 以上幾種類組合而成的字符類,如/a-z0-9\n/,匹配a-z的字母或者0-9的數字或者換行符 |
注意:在javascript類不能嵌套,就是不支持聯合類和交叉類,/a-m[p-z]/和/a-m[^b-e]/在JavaScript中是非法的
錨字符
字符 | 含義 |
---|---|
^ | 匹配字符串的開頭,在多行檢索中,匹配一行的開頭 |
$ | 匹配字符串的結尾,在多行檢索中,匹配一行的結尾 |
\b | 匹配單詞邊界。 |
\B | 匹配非單詞邊界。 |
量詞
簡單量詞
常用量詞 | {m,n}等價形式 | 描述 |
---|---|---|
? | {0,1} | 最多出現1次,例如,do(es)? 匹配 do 或 does 中的 do |
* | {0,} | 可能出現,也可能不出現,出現次數無上限,例如,zo* 匹配 z 和 zoo。 |
+ | {1,} | 最少出現1次,例如,zo+ 匹配 zo 和 zoo,但不匹配 z |
在正則表達式概念中,稱 +、*、?為常用量詞,稱{n,m}形式的為通用量詞。
使用情景舉例
**?的使用
**
情景:美式應用和英式語言的單詞寫法不同,比如traveler和traveller.
var str1 = 'traveler';
var str2 = 'traveller';
var pattern = /travell?er/;
console.log(pattern.test(str1));
console.log(str2.search(str2));
結果打印:
true
0
匹配各類標簽(前端應用)
- 匹配所以tag: /<[^>]+>/
- 匹配open tag: /<[/>][>]*>/
- 匹配close tag: /</[^>]+>/
- 匹配self-closing tag: /[^>/]+/>/
復雜量詞
- 貪婪量詞:先匹配整個字符串,如果不匹配則去掉最后一個字符再匹配,直到沒有任何字符。它是從后向前匹配。
所有簡單量詞都是貪婪的
。 - 惰性量詞:和貪婪量詞相反,即先匹配第一個字符,不匹配則匹配第一第二個字符,直到最后整個字符串。
所有簡單量詞后面加?就是惰性的了
。 - 支配量詞:只匹配整個字符串一次,不匹配就結束,也稱最懶量詞,
所有簡單量詞后面加+就是支配的了,但是javascript不支持,所以它連出場的機會也沒有了。
。
舉個栗子(complex-quantifiers.js):
var re1 = /.*bbb/g; // 定義貪婪量詞
var re2 = /.*?bbb/g; // 定義簡單惰性
// var re3 = /.*+bbb/g;//支配性,javascript不支持,nodejs報錯
var str='abbbaabbbaaabbb1234';
console.log(re1.test(str)); //true
console.log(re1.exec(str)); //null
console.log(str.match(re1)); //abbbaabbbaaabbbb
console.log(re2.test(str)); //true
console.log(re2.exec(str)); //aabbb
console.log(str.match(re2)); //abbb,aabbb,aaabbb
分組
到目前為止,我們只能一個字符到匹配,雖然量詞的出現,能幫助我們處理一排密緊密相連的同類型字符。但這是不夠的,下面該輪到小括號出場了,中括號表示范圍內選擇,大括號表示重復次數。小括號允許我們重復多個字符。
舉個栗子(group.js):
//分組+量詞
console.log(/(dog){2}/.test("dogdog"))//true
//分組+范圍
console.log("baddad".match(/([bd]ad?)*/))//baddad,dad
//分組+分組
console.log("mon and dad".match(/(mon( and dad)?)/))//mon and dad,mon and dad, and dad
優先級
優先級 | 符號 | 說明 |
---|---|---|
最高 | 轉義符 | |
高 | ( )、(?: )、(?= )、[ ] | 單元和字符類 |
中 | *、+、?、{n}、{n,}、{m,n} | 量詞 |
低 | ^、$、\任何元字符、任何字符 | 描點 |
最低 | | | 替換,選擇 |
參考加減乘除,先算括號內的記憶方式
RegExp對象
RegExp屬性
global 屬性 | ignoreCase 屬性 | multiline 屬性 | source 屬性
- global: 返回布爾值,該值指示使用正則表達式的 global 標志 (g) 的狀態。 默認值為 false。
只讀。
- ignoreCase: 返回布爾值,該值指示在正則表達式中使用的 ignoreCase 標志 (i) 的狀態。 默認值為 false。
只讀。
- multiline: 返回布爾值,該值指示在正則表達式中使用的 multiline 標志 (m) 的狀態。 默認值為 false。
只讀。
- source: 返回正則表達式模式的文本的一個副本。 只讀。
- lastIndex: 如果使用了全局模式,這個變量保存的是字符串中嘗試下次匹配的偏移值。在exec和test中都會用到這個變量。
可寫
RegExp方法
RegExp 對象有 3 個方法:test()、exec() 以及 compile()
RegExp.test(string)
test 方法檢查字符串中是否存在某種模式,如果存在,則返回 true,否則返回 false。test 方法不修改全局 RegExp 對象的屬性。
語法:
rgExp.test(str)
// 參數
rgExp 必需。 包含正則表達式模式和適用標志的 Regular Expression 對象的實例。
str 必需。 將對其執行搜索的字符串。
栗子:
var str = 'huangge is an handsome man';
var reg1 = new RegExp( 'handsome', 'g' );
var result = reg1.test(str);
console.log('huangge is an handsome man: ' + result);
RegExp.exec(string)
exec 方法使用正則表達式模式對字符串執行需找匹配,如果成功,則返回表示匹配信息的數組,否則返回null。默認情況下,它返回第一次匹配的結果
語法:
rgExp.exec(str)
// 參數
rgExp 必需。 包含正則表達式模式和適用標志的 Regular Expression 對象的實例。
str 必需。 對其執行搜索的 String 對象或字符串文本。
返回值
如果成功匹配,exec 方法返回一個數組,并且更新正則表達式對象的屬性。返回的數組包括匹配的字符串作為第一個元素,緊接著一個元素對應一個成功匹配被捕獲的字符串的捕獲括號(capturing parenthesis)。
如果匹配失敗,exec 方法將返回 null。
栗子(regexp-exec.js):
var reg= /\d{4}-\d{2}-\d{2}/g;
var str = 'aaa2015-08-11aaaaaabbss2015-08-22bbb';
var result = reg.exec(str);
console.log(result);
結果如下:
[ '2015-08-11',
index: 3,
input: 'aaa2015-08-11aaaaaabbss2015-08-22bbb' ]
RegExp.compile(string)
將正則表達式編譯為內部格式,從而更快地執行。
語法:
rgExp.compile(pattern, [flags])
// 參數
rgExp 必需。 Regular Expression 對象的一個實例。 可以是變量名或文本。
pattern 必需。 一個字符串表達式,包含要編譯的正則表達式模式
flags 可選。 可以組合使用的可用標志有:
g(全局搜索出現的所有模式)
i(忽略大小寫)
m(多行搜索)
compile 方法將 pattern 轉換為內部的格式,從而執行得更快。 例如,這允許在循環中更有效地使用正則表達式。 當重復使用相同的表達式時,編譯過的正則表達式使執行加速。 然而,如果正則表達式發生更改,則這種編譯毫無益處。
String的正則方法
String.match(RegExp)
這個方法類似RegExp.exec(string),只是調換了RegExp和string的位置。 另一個區別就是,無論是否指定全局,RegExp.exec(string)只是返回單詞匹配結果。 而string.match()會返回一個字符串數組,其中包含了各次匹配成功的文本
舉個栗子(string-match.js):
var reg= /\d{4}-\d{2}-\d{2}/g;
var str = 'aaa2015-08-11aaaaaabbss2015-08-22bbb';
var result = str.match(reg);
console.log(result);
打印的結果為:
[ '2015-08-11', '2015-08-22' ]
String.search(RegEexp)
這個用來尋找某個正則表達式在字符串第一次匹配成功的位置,如果不成功,則返回-1
舉個栗子(string-search.js):
var str1 = 'sssssaa111';
var str2 = 'sssssaaaaa';
var pattern = /\d/;
console.log ('st1 ' + str1.search(pattern));
console.log ('st2 ' + str2.search(pattern));
打印的結果為:
st1 7
st2 -1
String.replace(RegExp,replacement)
這個方法用來正則表達式替換。 將匹配到的文本替換為replacement。默認情況替換一次。如果設定了全局模式,則所有能匹配的文本都會替換。
舉個栗子(string-replace.js):
var reg = /\d{4}-\d{2}-\d{2}/;
var str = '2015-08-11 2015-08-22';
console.log(str.replace(reg, 'Date:'));
打印的結果為:
ate: 2015-08-22
String.split(RegExp [,limit])
這個方法使用一個正則表達式切分字符串,正則表達式是否使用全局對結果沒有影響
舉個栗子(string-split.js):
var str = 'one two three four';
var pattern = /\s+/;
console.log(str.split(pattern))
打印的結果為:
[ 'one', 'two', 'three', 'four' ]
常用的正則表達式
匹配中文字符的正則表達式: [\u4e00-\u9fa5]
匹配雙字節字符(包括漢字在內):[^\x00-\xff]
評注:可以用來計算字符串的長度(一個雙字節字符長度計2,ASCII字符計1)匹配空白行的正則表達式:\n\s*\r
匹配HTML標記的正則表達式:<(\S?)[^>]>.?</\1>|<.? />
匹配首尾空白字符的正則表達式:^\s|\s$
匹配Email地址的正則表達式:\w+([-+.]\w+)@\w+([-.]\w+).\w+([-.]\w+)*
匹配網址URL的正則表達式:[a-zA-z]+://[^\s]*
匹配帳號是否合法(字母開頭,允許5-16字節,允許字母數字下劃線):^[a-zA-Z][a-zA-Z0-9_]{4,15}$
匹配國內電話號碼:\d{3}-\d{8}|\d{4}-\d{7}
匹配騰訊QQ號:[1-9][0-9]{4,}
匹配中國郵政編碼:[1-9]\d{5}(?!\d)
匹配身份證:\d{15}|\d{18}
匹配ip地址:\d+.\d+.\d+.\d+
匹配特定數字
^[1-9]\d*$ //匹配正整數
^-[1-9]\d*$ //匹配負整數
^-?[1-9]\d*$ //匹配整數
^[1-9]\d*|0$ //匹配非負整數(正整數 + 0)
^-[1-9]\d*|0$ //匹配非正整數(負整數 + 0)
^[1-9]\d*\.\d*|0\.\d*[1-9]\d*$ //匹配正浮點數
^-([1-9]\d*\.\d*|0\.\d*[1-9]\d*)$ //匹配負浮點數
^-?([1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0)$ //匹配浮點數
^[1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0$ //匹配非負浮點數(正浮點數 + 0)
^(-([1-9]\d*\.\d*|0\.\d*[1-9]\d*))|0?\.0+|0$ //匹配非正浮點數(負浮點數 + 0)
匹配特定字符串
^[A-Za-z]+$ //匹配由26個英文字母組成的字符串
^[A-Z]+$ //匹配由26個英文字母的大寫組成的字符串
^[a-z]+$ //匹配由26個英文字母的小寫組成的字符串
^[A-Za-z0-9]+$ //匹配由數字和26個英文字母組成的字符串
^\w+$ //匹配由數字、26個英文字母或者下劃線組成的字符串