字符組 | 具體含義 | 記憶方式 |
---|---|---|
d | 表示 [0-9]。表示是一位數字。 | 其英文是 digit(數字) |
D | 表示 1。表示除數字外的任意字符。 | |
w | 表示 [0-9a-zA-Z_]。表示數字、大小寫字母和下劃線。 | w 是 word 的簡寫,也稱單詞字符。 |
W | 表示 2。非單詞字符。 | |
s | 表示 [ tvnrf]。表示空白符,包括空格、水平製表符、垂直製表符、換行符、回車符、換頁 符。 | s 是 space 的首字母,空白符的單詞是 white space。 |
S | 表示 3。 非空白符。 | |
. | 表示 4。通配符,表示幾乎任意字符。換行符、回車符、行分隔符和段分隔符 除外。 | 想一想省略號 ... 中的每一個點,均可以理解成佔位符,表示任何相似的東西。 |
[dD]/[wW]/[sS]/[^] | 任意字符 |
字符組 | 具體含義 | 記憶方式 |
---|---|---|
{m, } | 至少出現m次 | |
{m} | 等價於{m, m}, 出現m次 | |
? | 等價於{0, 1}, 出現或者不出現 | 問號的意思: 有麼? |
+ | 等價於{1, }, 表示至少出現一次 | 加號是追加的意思,表示必須現有一個,而後才考慮追加 |
* | 等價於{0, }, 出現任意次, 有可能不出現 | 看看天上的星星,可能一顆沒有,可能零散有幾顆,可能數也數不過來 |
字符組 | 具體含義 | 記憶方式 |
---|---|---|
g | 匹配全局 | 單詞是global |
i | 忽略字母大小寫 | 單詞是ignoreCase |
m | 多行匹配, 隻影響 ^ 和 $,兩者變成行的概念,即行開頭和行結尾 | 單詞是multiline |
字符組 | 具體含義 | 記憶方式 |
---|---|---|
^ | (脫字符)匹配開頭 | |
$ | (美圓符號)匹配結尾 | |
b | 單詞邊界 | w 與 W 之間的位置,也包括 w 與 ^ 之間的位置,和 w 與 $ 之間的位置 |
B | 非單詞邊界 | |
(?=p) | "p"的子模式, "p" 前面的位置 | positive lookahead(正向先行斷言) |
(?!p) | 非"p"前的位置 | negative lookahead(負向先行斷言) |
/^|$/g
: 匹配列/^|$/gm
: 匹配行, m
是既有修飾符(?<=p)
: positive lookbehind(正向後行斷言)(?<!p)
: negative lookbehind(負向後行斷言)千分位php
千分位示例1234567890
css
三位數字的前面: /(?=\d{3}$)/g
html
(?=p)
: 正向先行斷言多個三位數字: /(?=(\d{3})+$)/g
git
+
: 量詞, 多個最前面不匹配: /(?!^)(?=(\d{3})+$)/g
github
(?!^)
: 負向先行斷言非捕獲:正則表達式
正則: /\B(?=(?:\d{3})+(?!\d))/g
算法
帶空格的千分位123456789 123456789
thinkphp
/(?!\b)(?=(\d{3})+\b)/g
,即/(\B)(?=(\d{3})+\b)/g
^
和$
要替換成\b
格式化千分位編程
function format (num) { return num.toFixed(2).replace(/\B(?=(\d{3})+\b)/g, ",").replace(/^/, "$$ "); }; console.log( format(1888) ); // => "$ 1,888.00"
驗證密碼: 長度爲6~12位, 由數字、大寫字母和小寫字母,必須至少包含兩種字符vim
/^[0-9a-zA-Z]{6, 12}$/
至少包含兩種
解題核心
/(?=.*[0-9])/
劃分狀況
正則: /((?=.*[0-9])(?=.*[a-z])|(?=.*[0-9])(?=.*[A-Z])|(?=.*[a-z])(?=.*[A-Z]))^[0-9a-zA-Z]{6,12}$/
{6,12}
中間不能有空格不能同時所有爲一種(反向思路)
解題核心
/(?!^[0-9]{6,12}$)(^[0-9a-zA-Z]{6,12})/
劃分狀況
/(?!^[0-9]{6,12}$)(?!^[a-z]{6,12}$)(?!^[A-Z]{6,12}$)(^[0-9a-zA-Z]{6,12}$)/
詞法 | 含義 | 記憶方式 |
---|---|---|
(?=.[A-Z]) / (?=.?[A-Z]) / (.*[A-Z]) | 至少包含一個大寫字母 |
'ababa abbb ababab'.match(/(ab)+/g)
分支: (p1|p2)
示例
var regex = /^I love (JavaScript|Regular Expression)$/ console.log(regex.test("I love JavaScript")) // true console.log(regex.test("I love Regular Expression")) // true
分組方法
/^d{4}-d{2}-d{2}$/
/^(d{4})-(d{2})-(d{2})$/
提取數據:
match方法
'2017-06-12'.match(/(\d{4})-(\d{2})-(\d{2})/)
match返回數組: ["2017-06-12", "2017", "06", "12", index: 0, input: "2017-06-12", groups: undefined]
注意:
使用g
以後, 返回的是一個數組
'1s1'.match(/\d/g) => ["1", "1"]
null
exec方法
/(\d{4})-(\d{2})-(\d{2})/.exec('2017-06-12')
test
/match
/exec
)以後, 能夠經過RegExp
的$0
~$9
獲取替換: 轉換yyyy-mm-dd
爲dd/mm/yyyy
$
方法
'2019-09-23'.replace(/(\d{4})-(\d{2})-(\d{2})/, '$2/$3/$1')
RegExp.$
+function
方法
'2019-09-23'.replace(/(\d{4})-(\d{2})-(\d{2})/, function() { return `${RegExp.$2}/${RegExp.$3}/${RegExp.$1}` })
function
方法
'2019-09-23'.replace(/(\d{4})-(\d{2})-(\d{2})/, function(match, year, month, day) { return `${month}/${day}/${year}` })
\1
同時匹配日期格式: 2019-09-24
, 2019/09/24
, 2019.09.24
/\d{4}(-|\/|\.)\d{2}(-|\/|\.)\d{2}/
2019/09-24
一樣能匹配解決方法: 使用反向引用
/\d{4}(-|\/|\.)\d{2}(\1)\d{2}/
\2
是第二個分組引用, 依次類推括號嵌套
正則
// ["1231231233", "123", "1", "23", "3", index: 0, input: "1231231233", groups: undefined] 1231231233'.match(/^((\d)(\d(\d)))\1\2\3\4$/)
拆分
/^((\d)(\d(\d)))$/.test('123') // true
/^(\d)$/.test('1') // true
/^(\d(\d))$/.test('23') // true
/^(\d)$/.test('3') // true, 同第二個同樣
引用不存在的分組
會匹配反向引用自己
/\1/.test('\1') // true
分組後由量詞
會匹配到最後一次匹配
'12345'.match(/(\d)+/) // ["12345", "5", index: 0, input: "12345", groups: undefined]
/(\d)+ \1/.test('12345 5') // true
(?:p)
非捕獲匹配到的值不會保存起來
與之相反的是
舉例
'ababa abbb ababab'.match(/(?:ab)+/g) // ["abab", "ab", "ababab"] var regex = /^I love (?:JavaScript|Regular Expression)$/ regex.test("I love JavaScript") // true regex.test("I love Regular Expression") // true
' hello '.trim() // 'hello'
正則:
匹配到開頭和結尾的空字符串, 替換掉(效率高)
' hello '.replace(/^\s+|\s+$/g, '')
惰性匹配*?
, 匹配全部字符串, 提取相應數據
' hello '.replace(/^\s*(.*?)\s*$/, '$1') // 'hello'
方法
function titleize (str) { return str.toLowerCase().replace(/(?:^|\s)\w/g, function (c) { return c.toUpperCase(); }); } // My Name Is Epeli console.log( titleize('my name is epeli') )
注意
\s
: 製表符空格等, 用來匹配 name
這樣的數據方法
var camelize = function(str) { return str.replace(/[-_\s]+(.)?/g, function(match, c){ return c ? c.toUpperCase() : '' }) } console.log(camelize('-moz-transform'))
注意
replace: 關於replace參數
match
: 匹配到的字符串p1,p2,...
: 表明第n個括號匹配到的字符串offset
: 匹配到字符串在原字符串的偏移量string
: 被匹配的原字符串NamedCaptureGroup
: 命名捕獲組匹配的對象[-_\s]
: 連字符、下劃線和空白符?
: 應對單詞結尾不是單詞字符, 例如'-moz-transform '
方法
var dasherize = function(str) { return str.replace(/([A-Z])/g, '-$1').replace(/[-_\s]+/g, '-').toLowerCase() } console.log(dasherize('MozTTransform'))
或者使用function
var sperateLine = function(str) { return str.replace(/[A-Z]{1}/g, function(match) { return match ? `-${match.toLowerCase()}` : '' }) } console.log(sperateLine('MozTTransform'))
轉義
方法
var escapeHTML = function(str) { var escapeChars = { '<': 'lt', '>': 'gt', '"': 'quot', '&': 'amp', '\'': '#39' } return str.replace(new RegExp(`[${Object.keys(escapeChars).join('')}]`, 'g'), function(match) { return `&${escapeChars[match]};` }) } console.log(escapeHTML('<div>hello, \'world\'</div>'))
反轉義
方法
var unescapeHTML = function(str) { var htmlEntities = { 'lt': '<', 'gt': '>', 'quot': '"', 'amp': '&', '#39': '\'' } return str.replace(new RegExp(`\&([^;]+);`, 'g'), function(match, key) { console.log(match, key) return (key in htmlEntities) ? htmlEntities[key] : match }) } console.log(unescapeHTML('<div>hello, 'world'</div>'))
注意
關於/\&([^;]+);/g
中^
^
自己,使用\^
成對標籤
/<([^>]+)>[\d\D]*<\/\1>/
/<([^>]+)>[\d\D]*<\/\1>/.test('<title>wrong!</p>') // false
沒有回溯的匹配
/ab{1,3}c/.test('abbbc')
有回溯的匹配
/ab{1,3}c/.test('abbc')
建議: 應該避免
舉例
// .*任意字符出現任意次, 會匹配到abc"de, 匹配完以後發現還有"正則, 而後會回溯,只匹配到abc /".*"/.test('"abc"de') // 更改建議, 匹配非"的字符任意次, 碰到"就終止匹配, 減小回溯, 提升效率 /"[^"]*"/.test('"abc"de')
釋義
百度百科
回溯法也稱試探法,它的基本思想是:從問題的某一種狀態(初始狀態)出發,搜索從這種狀態出發 所能達到的全部「狀態」,當一條路走到「盡頭」的時候(不能再前進),再後退一步或若干步,從 另外一種可能「狀態」出發,繼續搜索,直到全部的「路徑」(狀態)都試探過。這種不斷「前進」、 不斷「回溯」尋找解的方法,就稱做「回溯法」。
常見的回溯形式
貪婪量詞
舉例
// ["12345", "123", "45", index: 0, input: "12345", groups: undefined] '12345'.match(/(\d{1,3})(\d{1,3})/)
惰性量詞
舉例
// ["1234", "1", "234", index: 0, input: "12345", groups: undefined] '12345'.match(/(\d{1,3}?)(\d{1,3})/)
會回溯的惰性
// ["12345", index: 0, input: "12345", groups: undefined] '12345'.match(/^\d{1,3}?\d{1,3}$/)
分支結構
分支也是惰性匹配
// ["can", index: 0, input: "candy", groups: undefined] 'candy'.match(/can|candy/)
總體匹配的話,也會回溯
// ["candy", index: 0, input: "candy", groups: undefined] 'candy'.match(/^(?:can|candy)$/)
總結
概念
NFA: 非肯定型有限自動機
結構的具體含義
結構 | 說明 | 舉例 |
---|---|---|
字面量 | 匹配一個具體字符,包含須要轉義和不須要轉義的 | 不轉義: /a/ 匹配字符'a' ; 轉義: /\n/ 匹配換行符, \. 匹配小數點 |
字符組 | 匹配一個字符,能夠是多種可能之一;反義字符組,表示除特定字符的其餘字符 | /[0-9]/ 表示匹配一個數字, 簡寫形式/\d/ ; [^0-9] 表示匹配一個非數字, 簡寫形式/\D/ |
量詞 | 表示一個字符連續出現; 或常見的簡寫形式 | /a{1,3}/ 表示a 字符連續出現1~3次; /a+/ 表示a 出現至少一次 |
錨 | 匹配一個位置, 而不是字符 | ^ 表示匹配位置的開頭, \b 表示匹配單詞邊界, (?=\d) 表示數字的前面 |
分組 | 用括號表示一個總體 | (ab)+ 表示ab 兩個字符連續出現屢次, 也可使用非捕獲組(?:ab)+ |
分支 | 多個子表達式多選一, 反向引用 | 引用1 表示匹配'abc' 或者'bcd' 字符子串; \2 表示引用第2個分組 |
引用1
: abc|bcd
操做符(從上至下)
操做符描述 | 操做符 | 優先級 |
---|---|---|
轉義符 | \ |
1 |
括號和方括號 | (...) 、(?:...) 、(?=...) 、(?!...) 、[...] |
2 |
量詞限定符 | {m} 、{m,n} 、{m,} 、? 、* 、+ |
3 |
位置和序列 | ^ 、$ 、\元字符 、通常字符 |
4 |
管道符(豎槓) | 引用1 |
5 |
引用1
: |
/ab?(c|de*)+|fg/
注意
匹配字符串總體問題
/^abc|bcd$/
/^(abc|bcd)$/
量詞連綴問題
每一個字符爲'a'
,'b'
,'c'
任選其一, 字符串長度是3的倍數
錯誤示例: /^[abc]{3}+$/
會報錯, 說
+
前沒有什麼可重複的
/([abc]{3})+/
元字符轉義問題
元字符
/\^\$\.\*\+\?\|\\\/\[\]\{\}\=\!\:\-\,/.test('^$.*+?|\\/[]{}=!:-,')
字符串中, 每一個字符轉義以後仍是自己
// true '^$.*+?|\\/[]{}=!:-,' === '\^\$\.\*\+\?\|\\\/\[\]\{\}\=\!\:\-\,'
不是每一個字符都須要轉義
跟字符組有關的[
、]
、 ^
、 -
。所以在會引發歧義的地方進行轉義, 例如^
, 不然會把整個字符組當作反義字符組
'^$.*+?|\\/[]{}=!:-,'.match(/[\^$.*+?|\\/\[\]{}=!:\-,]/g)
匹配'[abc]'
和{3,5}
/\[abc]/.test('[abc]') /\{3,5}/.test('{3,5}') /{,3}/.test('{,3}')
其餘
=
, !
, :
, -
, ,
不在特殊結構, 不須要轉義/\(123\)/
^
, $
, .
, *
, +
, ?
, |
, \
, /
等字符, 只要不在字符組內, 都須要轉義案例分析
/^(\d{15}|\d{17}[\dxX])$/
IPV4正則: /^((0{0,2}\d|0?\d{2}|1\d{2}|2[0-4]\d|25[0-5])\.){3}(0{0,2}\d|0?\d{2}|1\d{2}|2[0-4]\d|25[0-5])$/
((...)\.){3}(...)
3位數.3位數.3位數.3位數
拆分
0{0,2}\d
: 匹配
0~9 // 或 00~09 // 或 000~009
0?\d{2}
: 匹配
10~99 // 或 010~099
1\d{2}
: 匹配100
~199
2[0-4]\d
: 匹配200
~249
25[0-5]
: 匹配250
~255
平衡法則
構建正則前提
是否能使用正則
'1010010001...'
是否有必要使用(複雜)正則
字符串分隔舉例
var string = '2017-07-01' // 正則 var reg = /^(\d{4})-(\d{2})-(\d{2})/ console.log(string.match(reg)) // js api var stringArray = string.split('-') console.log(stringArray)
判斷是否有問號
var string = '?id=xx&act=search' // 正則 console.log(string.search(/\?/)) // js api console.log(string.indexOf('?'))
獲取子串
var string = 'JavaScript' // 正則 var reg = /.{4}(.+)/ console.log(string.match(reg)[1]) // js api console.log(string.substring(4))
是否有必要構建一個複雜的正則
/(?!^[0-9]{6,12}$)(?!^[a-z]{6,12}$)(?!^[A-Z]{6,12}$)^[0-9A-Za-z]{6,12}$/
分拆簡單正則:
var regex1 = /^[0-9a-zA-Z]{6,12}$/ var regex2 = /^[0-9]$/ var regex3 = /^[a-z]$/ var regex4 = /^[A-Z]$/ function checkPassword = function(string) { if (!regex1.test(string) return false if (regex2.test(string)) return false if (regex3.test(string)) return false if (regex4.test(string)) return false return true }
準確性
問題1:
055188888888
、0551-88888888
、(0551)88888888
分析(不考慮分機號和+86
)
/0\d{2,3}/
/[1-9]\d{6,7}/
055188888888
, 正則: /^0\d{2,3}[1-9]\d{6,7}$/
0551-88888888
, 正則: /^0\d{2,3}-[1-9]\d{6,7}$/
(0551)88888888
, 正則: /^\(0\d{2,3}\)[1-9]\d{6,7}$/
^/0\d{2,3}[1-9]\d{6,7}|0\d{2,3}-[1-9]\d{6,7}|\(0\d{2,3}\)[1-9]\d{6,7}$/
/^(0\d{2,3}|0\d{2,3}-|\(0\d{2,3}\))[1-9]\d{6,7}$/
/^(0\d{2,3}-?|\(0\d{2,3}\))[1-9]\d{6,7}$/
測試
/^(0\d{2,3}-?|\(0\d{2,3}\))[1-9]\d{6,7}$/.test('055188888888') /^(0\d{2,3}-?|\(0\d{2,3}\))[1-9]\d{6,7}$/.test('0551-88888888') /^(0\d{2,3}-?|\(0\d{2,3}\))[1-9]\d{6,7}$/.test('(0551)88888888') /^(0\d{2,3}-?|\(0\d{2,3}\))[1-9]\d{6,7}$/.test('051-8888888')
問題
問題2:
1.23
、+1.23
、-1.23
、10
、+10
、-10
、.2
、+.2
、-.2
分析
[+-]
\d+
\.\d+
1.23
、+1.23
、-1.23
正則: /^[+-]?\d+\.\d+$/
10
、+10
、-10
正則: /^[+-]?\d+$/
.2
、+.2
、-.2
正則: /^[+-]?\.\d+$/
/^[+-]?(\d+\.\d+|\d+|\.\d+)$/
另一種寫法: /^[+-]?(\d+)?(\.)?\d+$/
涉及到可維護性和可讀性
效率
正則運行階段
編譯
引擎報錯與否在這個階段
嘗試匹配
能夠優化的階段
匹配失敗,從下一位開始繼續第3步
能夠優化的階段
運行代碼示例
var regex = /\d+/g; // 0 ["123", index: 0, input: "123abc34def", groups: undefined] console.log( regex.lastIndex, regex.exec("123abc34def") ); // 3 ["34", index: 6, input: "123abc34def", groups: undefined] console.log( regex.lastIndex, regex.exec("123abc34def") ); // 8 null console.log( regex.lastIndex, regex.exec("123abc34def") ); // 0 ["123", index: 0, input: "123abc34def", groups: undefined] console.log( regex.lastIndex, regex.exec("123abc34def") );
當使用test
和exec
時, 正則有g
時, 起始位置是從lastIndex
開始的
優化方法
使用具體型字符組代替通配符, 來消除回溯
/".*"/.test('123"abc"456')
: 回溯有4次/".*?"/.test('123"abc"456')
: 回溯有2次
*?
/"[^"]*"/.test('123"abc"456')
: 無回溯使用非捕獲分組
不須要使用分組引用和反向引用時
/^[+-]?(\d+\.\d+|\d+|\.\d+)$/
=>/^[+-]?(?:\d+\.\d+|\d+|\.\d+)$/
獨立出肯定字符
/a+/
=> /aa*/
提取公共分支部分
可減小匹配過程當中的重複
/^abc|^bcd/
=> /^(abc|bcd)/
/this|that/
=> /th(?:is|at)/
減小分支的數量, 縮小它們範圍
/red|read/
=> /rea?d/
: 可讀性下降總結
準確性思路
正則表達式的四種操做
驗證: 判斷是否的操做
切分:
切分,
分隔的字符串
// ["html", "js", "css"] 'html,js,css'.split(/,/)
日期切割
// ["2019", "10", "11"] '2019/10/11'.split(/\D/) '2019.10.11'.split(/\D/) '2019-10-11'.split(/\D/)
提取:
search
'2019-10-11'.search(/^(\d{4})\D(\d{2})\D(\d{2})$/) // 2019 10 11 console.log(RegExp.$1, RegExp.$2, RegExp.$3)
match
// ["2019-10-11", "2019", "10", "11", index: 0, input: "2019-10-11", groups: undefined] '2019-10-11'.match(/^(\d{4})\D(\d{2})\D(\d{2})$/)
var date = [] '2019-10-11'.replace(/^(\d{4})\D(\d{2})\D(\d{2})$/, function(year, month, day) { date.push(year, month, day) }) // ["2019-10-11", "2019", "10"] console.log(date)
test
/^(\d{4})\D(\d{2})\D(\d{2})$/.test('2019-10-11') // 2019 10 11 console.log(RegExp.$1, RegExp.$2, RegExp.$3)
exec
/^(\d{4})\D(\d{2})\D(\d{2})$/.exec('2019-10-11') // 2019 10 11 console.log(RegExp.$1, RegExp.$2, RegExp.$3)
替換: 須要重點掌握
var tody = new Date('2019-10-11'.replace(/-/g, '/')) // Fri Oct 11 2019 00:00:00 GMT+0800 (China Standard Time) console.log(tody)
相關API注意要點
search
和match
會把字符串轉成正則
// 0 '2019.10.11'.search('.') // ["2", index: 0, input: "2019.10.11", groups: undefined] '2019.10.11'.match('.') // 4 '2019.10.11'.search('\\.') // [".", index: 4, input: "2019.10.11", groups: undefined] '2019.10.11'.match('\\.') // 4 '2019.10.11'.search(/\./) // [".", index: 4, input: "2019.10.11", groups: undefined] '2019.10.11'.match(/\./) // "2019/10.11" '2019.10.11'.replace('.', '/')
match
返回的格式問題: 與是否有修飾符g
有關
// ["2019", "2019", index: 0, input: "2019.10.11", groups: undefined] console.log('2019.10.11'.match(/\b(\d+)\b/)) // ["2019", "10", "11"] console.log('2019.10.11'.match(/\b(\d+)\b/g))
exec
比match
更強大: match
使用g
以後, 沒有關鍵信息index
, exec
能夠解決這個問題, 而且接着上一次繼續匹配
var string = "2019.10.11"; var regex2 = /\b(\d+)\b/g; // ["2019", "2019", index: 0, input: "2019.10.11", groups: undefined] console.log( regex2.exec(string) ); // 4 console.log( regex2.lastIndex); // ["10", "10", index: 5, input: "2019.10.11", groups: undefined] console.log( regex2.exec(string) ); // 7 console.log( regex2.lastIndex); // ["11", "11", index: 8, input: "2019.10.11", groups: undefined] console.log( regex2.exec(string) ); // 10 console.log( regex2.lastIndex); // null console.log( regex2.exec(string) ); // 0 console.log( regex2.lastIndex);
對使用exec
用法優化
示例中
lastIndex
表示下次匹配的開始位置
var string = '2019.10.11' var regex = /\b(\d+)\b/g var result while (result = regex.exec(string)) { console.log(result, regex.lastIndex) }
修飾符g
對exec
和test
的影響
字符串的四個方法, 每次匹配都是從0開始, 即lastIndex
屬性始終不變
var regex = /a/g 'a'.search(regex) // 0 console.log(regex.lastIndex) 'ab'.search(regex) // 0 console.log(regex.lastIndex)
正則的exec
和test
方法, 當正則含有g
, 每次匹配都會更改lastIndex
; 不含g
, 則不會改變lastIndex
var regex = /a/g // true 1 console.log( regex.test('a'), regex.lastIndex ) // true 3 console.log( regex.test('abac'), regex.lastIndex ) // false 0 console.log( regex.test('abacd'), regex.lastIndex )
test
總體匹配時須要^
和$
test
是看目標字符串中是否有子串符合條件
// true /123/.test('a123b') // false /^123$/.test('a123b') // true /^123$/.test('123')
split
相關事項
有2個參數, 第2個表示數組最大長度
// ["js", "css"] 'js,css,html'.split(/,/, 2)
使用分組, 則結果包含分隔符自己
// ["js", ",", "css", ",", "html"] 'js,css,html'.split(/(,)/)
replace
很強大
第二個參數是字符串時, 有以下含義
屬性 | 描述 |
---|---|
$1,$2,...,$99 | 匹配第1~99個分組裏捕獲到的文本 |
$& | 匹配到的子串文本 |
$` | 匹配到的子串左邊的文本 |
$' | 匹配到的子串右邊的文本 |
$$ | 美圓符號 |
把2,3,5
變成5=2+3
// "5=2+3" '2,3,5'.replace(/(\d+),(\d+),(\d+)/, '$3=$1+$2')
把2,3,5
變成222,333,555
'2,3,5'.replace(/(\d+)/g, '$&$&$&')
把2+3=5
變成2+3=2+3=5=5
// "2+3=2+3=5=5" '2+3=5'.replace(/(=)/, "$&$`$&$'$&")
第二個參數是函數時
replace
此時拿到的信息比exec
多
// ["1234", "1", "4", 0, "1234 2345 3456"] // ["2345", "2", "5", 5, "1234 2345 3456"] // ["3456", "3", "6", 10, "1234 2345 3456"] "1234 2345 3456".replace(/(\d)\d{2}(\d)/g, function (match, $1, $2, index, input) { // $1是每組數字的開始 // $2是每組數字的結束 console.log([match, $1, $2, index, input]); })
使用構造函數須要注意的問題
不推薦使用, 會寫不少的
\
// ["2017-06-27", "2017.06.27", "2017/06/27"] '2017-06-27 2017.06.27 2017/06/27'.match(/\d{4}(-|\.|\/)\d{2}\1\d{2}/g) // ["2017-06-27", "2017.06.27", "2017/06/27"] '2017-06-27 2017.06.27 2017/06/27'.match(new RegExp('\\d{4}(-|\\.|\\/)\\d{2}\\1\\d{2}', 'g'))
修飾符
修飾符 | 描述 | 單詞 |
---|---|---|
/g/ | 全局匹配(找到全部的) | global |
/i/ | 忽略字母大小寫 | ignoreCase |
/m/ | 多行匹配, 隻影響^ 和$ , 兩者變成行概念(行開頭、行結尾) |
multiline |
只讀屬性
var regex = /\w/img // true console.log(regex.global) // true console.log(regex.ignoreCase) // true console.log(regex.multiline)
source
屬性
對象屬性, 除了global
,ignoreCase
,multiline
,lastIndex
還有source
屬性; 用來構建動態正則, 或確認真正的正則
var className = "high"; // => (^|\s)high(\s|$) // => 即字符串"(^|\\s)high(\\s|$)" var regex = new RegExp("(^|\\s)" + className + "(\\s|$)"); console.log( regex.source ) console.log(regex.test(' high '), regex.test('high'))
構造函數屬性
靜態屬性隨着最後一次正則操做而變化, 除了
$1,...$9
, 還有幾個不太經常使用的(有兼容問題)
靜態屬性 | 描述 | 簡寫形式 |
---|---|---|
RegExp.input |
最近一次目標字符串 | RegExp['$_'] |
RegExp.lastMatch |
最近一次匹配的文本 | RegExp['$&'] |
RegExp.lastParen |
最近一次捕獲的文本 | RegExp['$+'] |
RegExp.leftContext |
目標匹配lastMatch以前的文本 | RegExp['$`'] |
RegExp.rightContext |
目標匹配lastMatch以後的文本 | RegExp["$'"] |
var regex = /([abc])(\d)/g var string = 'a1b2c3d4e5' string.match(regex) // a1b2c3d4e5 a1b2c3d4e5 console.log(RegExp.input, RegExp['$_']) // c3 c3 console.log(RegExp.lastMatch, RegExp['$&']) // 3 3 console.log(RegExp.lastParen, RegExp['$+']) // a1b2 c3 console.log(RegExp.leftContext, RegExp['$&']) // d4e5 d4e5 console.log(RegExp.rightContext, RegExp["$'"])
構造函數生成正則: 經過class獲取dom
function getClassByName(className) { var elements = document.getElementByTagName('*') var regex = new RegExp('(^|\\s)' + className + '($|\\s)') var result = [] var elementsLength = elements.length for (var i = 0; i < elementsLength; i++) { var element = elements[i] if (regex.test(element.className)) { result.push(element) } } return result }
字符串保存數據: 判斷數據類型
var utils = {} 'Boolean|Number|String|Function|Array|Date|RegExp|Object|Error'.split('|').forEach(function(item) { utils['is' + item] = function(obj) { return {}.toString.call(obj) === '[object '+ item +']' } }) console.log(utils.isArray([1, 2, 3]))
正則替代 &&(不兼容IE)
var readyRegex = /complete|loaded|interactive/ function ready(callback) { if (readyRegex.test(document.readyState) && document.body) { callback() } else { document.addEventListener('DomContentLoaded', function() { callback() }, false) } }
強大的replace: 參數查詢壓縮
function compress(source) { var keys = {} // [^=&]中的&不能去掉, 不然第二次會匹配成&b=2 // key不能爲空, value有可能爲空, 因此第一次是+, 第二次是* source.replace(/([^=&]+)=([^&])*/g, function(full, key, value) { keys[key] = (keys[key] ? keys[key] + ',' : '') + value }) var result = [] for (var key in keys) { result.push(key + '=' + keys[key]) } return result.join('&') } // a=1,3&b=2,4 console.log(compress('a=1&b=2&a=3&b=4'))
根據字符串生成正則
function createRegex(regex) { try { if (regex[0] === '/') { regex = regex.split('/') regex.shift() var flags = regex.pop() regex = regex.join('/') regex = new RegExp(regex, flags) } else { regex = new RegExp(regex, 'g') } return { success: true, result: regex } } catch (e) { return { success: false, message: '無效的正則表達式' } } } // {success: true, result: /\d/gm} console.log(createRegex('/\\d/gm')) // {success: true, result: /\d/g} console.log(createRegex('/\\d/g'))
教程類
文檔類
實用?
網址校驗
工具