正則表達式不論是先後端開發,都是很容易碰到的痛點,就像前女朋友同樣時不時的讓你這麼痛一下,最近抽空從新學習了下js裏面的正則表達式,隨記之。正常水平本文閱讀須要10分鐘便可,10分鐘回顧知識點鞏固一下基礎。javascript
1. 實例化兩種方式html
var reg = /\bis\b/g; // 自變量 var reg = new RegExp('\\bis\\b','g'); // 對象實例化方式,好處是能夠傳遞變量進來
2. 修飾符 或者叫作 對象只讀屬性java
global:是否全文搜索,默認false reg.global ignoreCase:是否大小寫敏感,默認是false reg.ignoreCase multiline:多行搜索,默認值是false lastIndex:當前表達式匹配內容的最後一個字符的下一個位置 source:正則表達式的文本字符串
這些屬性咱們能夠在正則對象的實例化對象身上看的到,也是咱們正則表達式的修飾符號。git
3. 常見的表達式模式正則表達式
[abc] 查找方括號之間的任何字符。 [0-9] 查找任何從 0 至 9 的數字。 (x|y) 查找任何以 | 分隔的選項。
4. 元字符後端
(1)**原義文本字符**:表明它原來含義的字符 例如:abc、123 (2)**元字符**:在正則表達式中有特殊意義的非字母字符 例如:\b表示匹配單詞邊界, (3) 在正則表達式中具體特殊含義的字符:* + ? $ ^ . \ () {} []
5. 字符類數組
通常狀況下正則表達式一個字符對應字符串一個字符, 表達式 ab\t 的含義是: 一個字母a一個字母b加一個水平製表符 \r 回車 \n 換行。app
可使用元字符[]來構建一個簡單的【類】,所謂類是指符合某些特徵的對象,一個泛指,而不是特指某個字符,例如表達式[abc]:把字符 a 或 b 或 c 歸爲一類,表達式能夠匹配這類的字符,即匹配abc中的,可是 [^abc] 是取反的意思。xss
6. 範圍類學習
正則表達式提供了範圍類,可使用[a-z]來鏈接兩個字符類表示從a到z的任意字符,這是一個閉區間,也就是包含a和z;
能夠進行連寫:[a-zA-Z],可是若是同時範圍內包含字符"-":如[0-9-] :"2012-08-08".replace(/[0-9-]/,'');
7: 預約義類 匹配常見的字符類
. 等價於 [^\r\n] 表示除了回車符和換行符以外的全部的字符 \d 等價於 [0-9] 數字字符 d:digit \D [^0-9] 非數字字符 \s 等價於 [\t\n\x0B\f\r] 空白符 s:space \S 非空白符號 \w 等價於 [a-zA-Z_0-9] 單詞字符(字母、數字下劃線) w:word 邊界匹配 ^ 以XXX開始 $ 以XXX結束 \b 單詞邊界 \B 非單詞邊界
8 量詞: 做用於緊挨着的字母,並非整個單詞,須要分組才能拿到整個單詞
? 出現0或1次(最多1次) + 出現1或屢次(至少1次) * 出現0或屢次(任意次) {n} 出現n次 {n,m} 出現n到m次 {n,} 至少出現n次 量詞放在元字符後面,如\d+
9:兩種模式
**貪婪模式**:儘量多地匹配,直到匹配失敗 即匹配過程當中有多個條件符合的話,會選擇最多的那一種 **非貪婪模式**:讓正則表達式儘量少的匹配,一旦成功匹配則再也不繼續嘗試,**在【量詞】後面加上【?】便可** eg: '12345678'.replace(/\d{3,6}/g,'X') "X78"貪婪模式:儘量多的匹配 '12345678'.replace(/\d{3,6}?/g,'X') "XX78"非貪婪模式:儘量少的匹配
10 分組
(1) 使用()能夠達到分組的功能,使量詞做用於分組 (Byron){3},若是直接Byron{3}則匹配到的三Byronnn。 默認是貪婪的捕獲性質的分組。
例子:小寫字母連續出現3次 'a1b2c3d4'.replace(/[a-z]\d{3}/g,'Q'); //"a1b2c3d4" 'a1b2c3d4'.replace(/([a-z]\d){3}/g,'Q'); //"Qd4" // 經過$1 _ 取到捕獲到的值。 var str = 'hello world'; var pattern = /([a-z]+)\s([a-z]+)/; console.log(RegExp.$1) //'hello' 第一個分組([a-z]+)的值 // 捕獲性的分組 var str1 = '000aaa111'; var pattern = /([a-z]+)(\d+)/; //捕獲性分組匹配 var arr = pattern.exec(str1); console.log(arr) // ['aaa111','aaa','111'] 結果子串也獲取到了,這並非咱們想要的結果
(2). 使用 將正則表達式分紅先後兩部分 【或 |】
'ByrCasperByronsper'.replace(/Byr(on|Ca)sper/g,'Q'); // "QQ"
(3).反向引用 反向引用,捕獲必須是在分組的基礎之上進行操做的,後續案例中還要補充這個點。
例如 2015-12-25 => 12/25/2015
在分組的基礎上,分組取值使用'$1 $2....'表明捕獲分組內容。
(4). 非捕獲性的分組,不但願捕獲某些分組,只須要在分組內加上 ?:
便可
例如'2015-07-09'.replace(/(?:\d{4})-(\d{2})-(\d{2})/g,'$2/$3/$1')
; // "09/$3/07"
//非捕獲性分組 var str2 = '000aaa111'; var pattern2 = /(?:[a-z]+)(?:\d+)/; //非捕獲性分組匹配 var arr2 = pattern2.exec(str2); console.log(arr2) //['aaa111'] 結果正確
11 前瞻
js 不支持後顧 eg: 匹配到張三,並且還要看看他爹是否是叫李四
正則表達式從文本頭部向尾部開始解析,文本尾部方向爲「前」,頭部方向爲「後」
前瞻:正則表達式匹配到規則的時候,向前檢查是否符合斷言,後顧/後瞻方向相反(javascript不支持)
符合斷言:確定/正向匹配 正向前瞻:exp(?=assert) 不符合斷言:否認/負向匹配 負向前瞻:exp(?!assert)
很重要的一點是, 前瞻中斷言只做爲判斷條件,不參與規則部分的操做
12 正則相關的一些方法
test 不支持全局匹配 RegExp.prototype = { test: 不支持全局匹配 re.test(str) 重點在於檢測 返回true/false : 返回數組【匹配項目,有子正則的話輸出子匹配項目,具體哪個開始匹配index】 } String.prototype = { search: 找不到返回-1 str.seach(re); match: 返回匹配到的數組 str.match(re) 若是沒有g只會匹配一次 replace: split }
**(1) is替換** const s = 'this is a book'.replace(/\bis\b/,'~'); // "this ~ a book" const s1 = 'this is a book'.replace(/\Bis\b/,'~'); // "th~ is a book"
**(2) 把http 而且結尾是jpg的url 刪除協議頭,即返回//...jpg** https://cdn.baidu.com/images/asdas.jpg http://cdn.hexun.com/images/asdas.jpg https://cdn.baidu.com/images/asdas.png http://cdn.sohu.com/images/asdas.jpg https://cdn.baidu.com/images/asdas.jpg http://cdn.baidu.com/images/asdas.png https://cdn.baidu.com/images/asdas.png 正則:`/^http:(\/\/.+\.jpg)$/gi`
(3) 把下面是日期的所有替換爲: 月-日-年 02-03-2006 test/07/sd 05-10-2015 16555/12/45 1253645/2131/34 05-15-1998 正則:str.replace( /^(\d{4})[/-](\d{2})[/-](\d{2})$/ $2-$3-$1)
(4) // 正向前瞻 const s4 = 'v3asd7*5sd'.replace(/\w(?=\d)/g,'~'); // "~3as~7*5sd" // 負向前瞻 注意匹配項 是分組的結果 注意爲何沒有使用全局匹配? const s5 = 'v3asd7*5sd'.replace(/\w(?!\d)/,'~'); // "v~asd7*5sd"
(5) // 非捕獲性的分組是不會做爲匹配項返回的 const str_0 = 'window 98 is ok 11'; const re_0 = /window (?=\d)/g; // 乾脆不會做爲結果出現 const re_1 = /window (?:\d+)/g; // 非捕獲性分組定義子表達式能夠做爲總體被修飾可是子表達式匹配結果不會被存儲。 const re_2 = /window (\d+)/g; // 會做爲匹配項目出如今子 console.log( re_0.exec(str_0) ); console.log( re_1.exec(str_0) ); console.log( re_2.exec(str_0) ); 結果是: [ 'window ', index: 0, input: 'window 98 is ok 11' ] [ 'window 98', index: 0, input: 'window 98 is ok 11' ] [ 'window 98', '98', index: 0, input: 'window 98 is ok 11' ]
(6) var str_img = "img1.jpg,img2.jpg,img3.bmp"; var str_re_1 = /(?:\w+)(?=\.jpg)/g; var str_re_2 = /(?:\w+)(?:\.jpg)/g; console.log( str_img.match(str_re_1) ) //[ 'img1', 'img2' ] console.log( str_img.match(str_re_2) ) // [ 'img1.jpg', 'img2.jpg' ] // 上面使用的是match可是看下面代碼執行的結果 console.log( str_re_1.exec(str_img) ); 輸出結果[ 'img1', index: 0, input: 'img1.jpg,img2.jpg,img3.bmp' ] 爲何不是所有的呢? 再看一下代碼 var result; while ( (result= str_re_1.exec(str_img)) !=null ){ console.log(str_re_1.lastIndex) console.log(result) } >> 執行的結果是: 4 [ 'img1', index: 0, input: 'img1.jpg,img2.jpg,img3.bmp' ] 13 [ 'img2', index: 9, input: 'img1.jpg,img2.jpg,img3.bmp' ] 總結出,exec 不是全局的匹配結果
(7)手機號碼中間4位 **** console.log( '15201095029'.replace(/(?:\d{4})(?=\d{4}$)/g,function($,$1){ return '****' }) );
(8)轉換爲駝峯的寫法 console.log( 'app-com-up'.replace(/-(\w)/g,function($,$1){ return $1.toUpperCase() }) ); (9)貪婪匹配 .+是非貪婪匹配 .+?是貪婪匹配
// 如,把用戶輸入的特殊字符進行轉義,以免xss攻擊 function htmlEscape(text) { return text.replace(/[<>"&]/g, function (match, pos, originalText) { switch (match) { case '<': return '<' break; case '>': return '>' break; case '\"': return '"' break; case '&': return '&' break; } }) }