正則表達式(regular expression)描述了一種字符串匹配的模式,能夠用來檢查一個字符串是否含有某種子串、將匹配的子串作替換或者從某個字符串中取出符合某個條件的子串等。node
說白了正則表達式就是處理字符串的,咱們能夠用它來處理一些複雜的字符串。git
咱們直接用一個例子來講明github
//找出這個字符串中的全部數字 var str = 'abc123de45fgh6789qqq111'; //方法1 function findNum(str) { var tmp = '', arr = []; for (var i = 0; i < str.length; i++) { var cur = str[i]; if (!isNaN(cur)) { tmp += cur; } else { if (tmp) { arr.push(tmp); tmp = ''; } } } if (tmp) { arr.push(tmp) } return arr; } console.log(findNum(str)) //["123", "45", "6789", "111"] //方法2 使用正則表達式 var reg = /\d+/g; console.log(str.match(reg)) // ["123", "45", "6789", "111"]
經過比較2種方法咱們明顯看出在對字符串進行處理時,使用正則表達式會簡單許多,因此雖然正則表達式看起來像是火星文同樣的一堆亂碼的東西,但咱們仍是有必要去學習它的。正則表達式
var reg = /pattern/flags // 字面量建立方式 var reg = new RegExp(pattern,flags); //實例建立方式 pattern:正則表達式 flags:標識(修飾符) 標識主要包括: 1. i 忽略大小寫匹配 2. m 多行匹配,即在到達一行文本末尾時還會繼續尋常下一行中是否與正則匹配的項 3. g 全局匹配 模式應用於全部字符串,而非在找到第一個匹配項時中止
字面量建立方式和構造函數建立方式的區別express
var regParam = 'cm'; var reg1 = new RegExp(regParam+'1'); var reg2 = /regParam/; console.log(reg1); // /cm1/ console.log(reg2); // /regParam/
var reg1 = new RegExp('\d'); // /d/ var reg2 = new RegExp('\\d') // /\d/ var reg3 = /\d/; // /\d/
表明特殊含義的元字符數組
\d : 0-9之間的任意一個數字 \d只佔一個位置 \w : 數字,字母 ,下劃線 0-9 a-z A-Z _ \s : 空格或者空白等 \D : 除了\d \W : 除了\w \S : 除了\s . : 除了\n以外的任意一個字符 \ : 轉義字符 | : 或者 () : 分組 \n : 匹配換行符 \b : 匹配邊界 字符串的開頭和結尾 空格的兩邊都是邊界 => 不佔用字符串位數 ^ : 限定開始位置 => 自己不佔位置 $ : 限定結束位置 => 自己不佔位置 [a-z] : 任意字母 []中的表示任意一個均可以 [^a-z] : 非字母 []中^表明除了 [abc] : abc三個字母中的任何一個 [^abc]除了這三個字母中的任何一個字符
表明次數的量詞元字符函數
* : 0到多個 + : 1到多個 ? : 0次或1次 無關緊要 {n} : 正好n次; {n,} : n到屢次 {n,m} : n次到m次
量詞出如今元字符後面 如\d+,限定出如今前面的元字符的次數學習
var str = '1223334444'; var reg = /\d{2}/g; var res = str.match(reg); console.log(res) //["12", "23", "33", "44", "44"] var str =' 我是空格君 '; var reg = /^\s+|\s+$/g; //匹配開頭結尾空格 var res = str.replace(reg,''); console.log('('+res+')') //(我是空格君)
正則中的()和[]和重複子項 //拿出來單獨說一下this
var str1 = 'abc'; var str2 = 'dbc'; var str3 = '.bc'; var reg = /[ab.]bc/; //此時的.就表示. reg.test(str1) //true reg.test(str2) //false reg.test(str3) //true
[12]表示1或者2 不過[0-9]這樣的表示0到9 [a-z]表示a到z 例如:匹配從18到65年齡段全部的人 var reg = /[18-65]/; // 這樣寫對麼 reg.test('50') //Uncaught SyntaxError: Invalid regular expression: /[18-65]/: Range out of order in character class //聰明的你想多是8-6這裏不對,因而改爲[16-85]彷佛能夠匹配16到85的年齡段的,但實際上發現這也是不靠譜的 實際上咱們匹配這個18-65年齡段的正則咱們要拆開來匹配 咱們拆成3部分來匹配 18-19 20-59 60-65 reg = /(18|19)|([2-5]\d)|(6[0-5])/;
()的提升優先級功能:凡有|出現的時候,咱們必定要注意是否有必要加上()來提升優先級;url
()的分組 重複子項 (兩個放到一塊兒說)
分組: 只要正則中出現了小括號那麼就會造成一份分組 只要有分組,exec(match)和replace中的結果就會發生改變(後邊的正則方法中再說) 分組的引用(重複子項) : 只要在正則中出現了括號就會造成一個分組,咱們能夠經過\n (n是數字表明的是第幾個分組)來引用這個分組,第一個小分組咱們能夠用\1來表示 例如:求出這個字符串'abAAbcBCCccdaACBDDabcccddddaab'中出現最多的字母,並求出出現多少次(忽略大小寫)。 var str = 'abbbbAAbcBCCccdaACBDDabcccddddaab'; str = str.toLowerCase().split('').sort(function(a,b){return a.localeCompare(b)}).join(''); var reg = /(\w)\1+/ig; var maxStr = ''; var maxLen = 0; str.replace(reg,function($0,$1){ var regLen = $0.length; if(regLen>maxLen){ maxLen = regLen; maxStr = $1; }else if(maxLen == regLen){ maxStr += $1; } }) console.log(`出現最多的字母是${maxStr},共出現了${maxLen}次`)
var str = 'aaabbb'; var reg = /(a+)(?:b+)/; var res =reg.exec(str); console.log(res) //["aaabbb", "aaa", index: 0, input: "aaabbb"] //只捕獲第一個小分組的內容
下面是常見的運算符的優先級排列 依次從最高到最低說明各類正則表達式運算符的優先級順序: \ : 轉義符 (), (?:), (?=), [] => 圓括號和方括號 *, +, ?, {n}, {n,}, {n,m} => 量詞限定符 ^, $, \任何元字符、任何字符 | => 替換,"或"操做 字符具備高於替換運算符的優先級,通常用 | 的時候,爲了提升 | 的優先級,咱們經常使用()來提升優先級 如: 匹配 food或者foot的時候 reg = /foo(t|d)/ 這樣來匹配
貪婪性
所謂的貪婪性就是正則在捕獲時,每一次會盡量多的去捕獲符合條件的內容。
若是咱們想盡量的少的去捕獲符合條件的字符串的話,能夠在量詞元字符後加?
懶惰性
懶惰性則是正則在成功捕獲一次後無論後邊的字符串有沒有符合條件的都再也不捕獲。
若是想捕獲目標中全部符合條件的字符串的話,咱們能夠用標識符g來標明是全局捕獲
var str = '123aaa456'; var reg = /\d+/; //只捕獲一次,一次儘量多的捕獲 var res = str.match(reg) console.log(res) // ["123", index: 0, input: "123aaa456"] reg = /\d+?/g; //解決貪婪性、懶惰性 res = str.match(reg) console.log(res) // ["1", "2", "3", "4", "5", "6"]
這裏咱們只介紹test、exec、match和replace這四個方法
var str = 'abc'; var reg = /\w+/; console.log(reg.test(str)); //true
var str = 'abc123cba456aaa789'; var reg = /\d+/; console.log(reg.exec(str)) // ["123", index: 3, input: "abc123cba456aaa789"]; console.log(reg.lastIndex) // lastIndex : 0 reg.exec捕獲的數組中 // [0:"123",index:3,input:"abc123cba456aaa789"] 0:"123" 表示咱們捕獲到的字符串 index:3 表示捕獲開始位置的索引 input 表示原有的字符串
當咱們用exec進行捕獲時,若是正則沒有加'g'標識符,則exec捕獲的每次都是同一個,當正則中有'g'標識符時 捕獲的結果就不同了,咱們仍是來看剛剛的例子
var str = 'abc123cba456aaa789'; var reg = /\d+/g; //此時加了標識符g console.log(reg.lastIndex) // lastIndex : 0 console.log(reg.exec(str)) // ["123", index: 3, input: "abc123cba456aaa789"] console.log(reg.lastIndex) // lastIndex : 6 console.log(reg.exec(str)) // ["456", index: 9, input: "abc123cba456aaa789"] console.log(reg.lastIndex) // lastIndex : 12 console.log(reg.exec(str)) // ["789", index: 15, input: "abc123cba456aaa789"] console.log(reg.lastIndex) // lastIndex : 18 console.log(reg.exec(str)) // null console.log(reg.lastIndex) // lastIndex : 0 每次調用exec方法時,捕獲到的字符串都不相同 lastIndex :這個屬性記錄的就是下一次捕獲從哪一個索引開始。 當未開始捕獲時,這個值爲0。 若是當前次捕獲結果爲null。那麼lastIndex的值會被修改成0.下次從頭開始捕獲。 並且這個lastIndex屬性還支持人爲賦值。
exec的捕獲還受分組()的影響
var str = '2017-01-05'; var reg = /-(\d+)/g // ["-01", "01", index: 4, input: "2017-01-05"] "-01" : 正則捕獲到的內容 "01" : 捕獲到的字符串中的小分組中的內容
//match和exec的用法差很少 var str = 'abc123cba456aaa789'; var reg = /\d+/; console.log(reg.exec(str)); //["123", index: 3, input: "abc123cba456aaa789"] console.log(str.match(reg)); //["123", index: 3, input: "abc123cba456aaa789"]
上邊兩個方法console的結果有什麼不一樣呢?二個字符串是同樣滴。
當咱們進行全局匹配時,兩者的不一樣就會顯現出來了.
var str = 'abc123cba456aaa789'; var reg = /\d+/g; console.log(reg.exec(str)); // ["123", index: 3, input: "abc123cba456aaa789"] console.log(str.match(reg)); // ["123", "456", "789"]
當全局匹配時,match方法會一次性把符合匹配條件的字符串所有捕獲到數組中,
若是想用exec來達到一樣的效果須要執行屢次exec方法。
咱們能夠嘗試着用exec來簡單模擬下match方法的實現。
String.prototype.myMatch = function (reg) { var arr = []; var res = reg.exec(this); if (reg.global) { while (res) { arr.push(res[0]); res = reg.exec(this) } }else{ arr.push(res[0]); } return arr; } var str = 'abc123cba456aaa789'; var reg = /\d+/; console.log(str.myMatch(reg)) // ["123"] var str = 'abc123cba456aaa789'; var reg = /\d+/g; console.log(str.myMatch(reg)) // ["123", "456", "789"]
此外,match和exec均可以受到分組()的影響,不過match只在沒有標識符g的狀況下才顯示小分組的內容,若是有全局g,則match會一次性所有捕獲放到數組中
var str = 'abc'; var reg = /(a)(b)(c)/; console.log( str.match(reg) ); // ["abc", "a", "b", "c", index: 0, input: "abc"] console.log( reg.exec(str) ); // ["abc", "a", "b", "c", index: 0, input: "abc"] 當有全局g的狀況下 var str = 'abc'; var reg = /(a)(b)(c)/g; console.log( str.match(reg) ); // ["abc"] console.log( reg.exec(str) ); // ["abc", "a", "b", "c", index: 0, input: "abc"]
正則去匹配字符串,匹配成功的字符去替換成新的字符串 寫法:str.replace(reg,newStr); var str = 'a111bc222de'; var res = str.replace(/\d/g,'Q') console.log(res) // "aQQQbcQQQde" replace的第二個參數也能夠是一個函數 str.replace(reg,fn); var str = '2017-01-06'; str = str.replace(/-\d+/g,function(){ console.log(arguments) }) 控制檯打印結果: ["-01", 4, "2017-01-06"] ["-06", 7, "2017-01-06"] "2017undefinedundefined" 從打印結果咱們發現每一次輸出的值彷佛跟exec捕獲時很類似,既然與exec彷佛很類似,那麼彷佛也能夠打印出小分組中的內容嘍 var str = '2017-01-06'; str = str.replace(/-(\d+)/g,function(){ console.log(arguments) }) ["-01", "01", 4, "2017-01-06"] ["-06", "06", 7, "2017-01-06"] "2017undefinedundefined" 從結果看來咱們的猜想沒問題。 此外,咱們須要注意的是,若是咱們須要替換replace中正則找到的字符串,函數中須要一個返回值去替換正則捕獲的內容。
經過replace方法獲取url中的參數的方法
(function(pro){ function queryString(){ var obj = {}, reg = /([^?&#+]+)=([^?&#+]+)/g; this.replace(reg,function($0,$1,$2){ obj[$1] = $2; }) return obj; } pro.queryString = queryString; }(String.prototype)); // 例如 url爲 https://www.baidu.com?a=1&b=2 // window.location.href.queryString(); // {a:1,b:2}
用於查找在某些內容(但並不包括這些內容)以前或以後的東西,如\b,^,$那樣用於指定一個位置,這個位置應該知足必定的條件(即斷言),所以它們也被稱爲零寬斷言。
在使用正則表達式時,捕獲的內容先後必須是特定的內容,而咱們又不想捕獲這些特定內容的時候,零寬斷言就能夠派上用場了。
這四胞胎看着名字好長,給人一種好複雜好難的感受,咱們仍是挨個來看看它們到底是幹什麼的吧。
var str = "i'm singing and dancing"; var reg = /\b(\w+(?=ing\b))/g var res = str.match(reg); console.log(res) // ["sing", "danc"] 注意一點,這裏說到的是位置,不是字符。 var str = 'abc'; var reg = /a(?=b)c/; console.log(res.test(str)); // false // 這個看起來彷佛是正確的,實際上結果是false reg中a(?=b)匹配字符串'abc' 字符串a的右邊是b這個匹配沒問題,接下來reg中a(?=b)後邊的c匹配字符串時是從字符串'abc'中a的後邊b的前邊的這個位置開始匹配的, 這個至關於/ac/匹配'abc',顯然結果是false了
var str = 'nodejs'; var reg = /node(?!js)/; console.log(reg.test(str)) // false
var str = '¥998$888'; var reg = /(?<=\$)\d+/; console.log(reg.exec(str)) //888
var str = '¥998$888'; var reg = /(?<!\$)\d+/; console.log(reg.exec(str)) //998
最後,來一張思惟導圖
圖片若是放大也看不清的話 下載地址 若有錯誤歡迎指正!