一、是什么
正則表達式是一種用來匹配字符串的強有力的武器
它的設計思想是用一種描述性的語言定義一個規則,凡是符合規則的字符串,我們就認為它“匹配”了,否則,該字符串就是不合法的
在?JavaScript
中,正則表達式也是對象,構建正則表達式有兩種方式:
- 字面量創建,其由包含在斜杠之間的模式組成
const re = /\d+/g;
- 調用
RegExp
對象的構造函數
const re = new RegExp("\\d+","g");const rul = "\\d+"
const re1 = new RegExp(rul,"g");
使用構建函數創建,第一個參數可以是一個變量,遇到特殊字符\
需要使用\\
進行轉義
二、匹配規則
常見的校驗規則如下:
規則 | 描述 |
---|---|
\ | 轉義 |
^ | 匹配輸入的開始 |
$ | 匹配輸入的結束 |
* | 匹配前一個表達式 0 次或多次 |
+ | 匹配前面一個表達式 1 次或者多次。等價于?{1,} |
? | 匹配前面一個表達式 0 次或者 1 次。等價于{0,1} |
. | 默認匹配除換行符之外的任何單個字符 |
x(?=y) | 匹配'x'僅僅當'x'后面跟著'y'。這種叫做先行斷言 |
(?<=y)x | 匹配'x'僅當'x'前面是'y'.這種叫做后行斷言 |
x(?!y) | 僅僅當'x'后面不跟著'y'時匹配'x',這被稱為正向否定查找 |
(?<!y)x | 僅僅當'x'前面不是'y'時匹配'x',這被稱為反向否定查找 |
x|y | 匹配‘x’或者‘y’ |
{n} | n 是一個正整數,匹配了前面一個字符剛好出現了 n 次 |
{n,} | n是一個正整數,匹配前一個字符至少出現了n次 |
{n,m} | n 和 m 都是整數。匹配前面的字符至少n次,最多m次 |
[xyz] | 一個字符集合。匹配方括號中的任意字符 |
[^xyz] | 匹配任何沒有包含在方括號中的字符 |
\b | 匹配一個詞的邊界,例如在字母和空格之間 |
\B | 匹配一個非單詞邊界 |
\d | 匹配一個數字 |
\D | 匹配一個非數字字符 |
\f | 匹配一個換頁符 |
\n | 匹配一個換行符 |
\r | 匹配一個回車符 |
\s | 匹配一個空白字符,包括空格、制表符、換頁符和換行符 |
\S | 匹配一個非空白字符 |
\w | 匹配一個單字字符(字母、數字或者下劃線) |
\W | 匹配一個非單字字符 |
正則表達式標記
標志 | 描述 |
---|---|
g | 全局搜索。 |
i | 不區分大小寫搜索。 |
m | 多行搜索。 |
s | 允許?. ?匹配換行符。 |
u | 使用unicode 碼的模式進行匹配。 |
y | 執行“粘性(sticky )”搜索,匹配從目標字符串的當前位置開始。 |
使用方法如下:
var re = /pattern/flags;
var re = new RegExp("pattern", "flags");
在了解下正則表達式基本的之外,還可以掌握幾個正則表達式的特性:
貪婪模式
在了解貪婪模式前,首先舉個例子:
const reg = /ab{1,3}c/
在匹配過程中,嘗試可能的順序是從多往少的方向去嘗試。首先會嘗試bbb
,然后再看整個正則是否能匹配。不能匹配時,吐出一個b
,即在bb
的基礎上,再繼續嘗試,以此重復
如果多個貪婪量詞挨著,則深度優先搜索
const string = "12345";
const regx = /(\d{1,3})(\d{1,3})/;
console.log( string.match(reg) );
// => ["12345", "123", "45", index: 0, input: "12345"]
其中,前面的\d{1,3}
匹配的是"123",后面的\d{1,3}
匹配的是"45"
懶惰模式
惰性量詞就是在貪婪量詞后面加個問號。表示盡可能少的匹配
其中\d{1,3}?
只匹配到一個字符"1",而后面的\d{1,3}
匹配了"234"
分組
分組主要是用過()
進行實現,比如beyond{3}
,是匹配d
字母3次。而(beyond){3}
是匹配beyond
三次
在()
內使用|
達到或的效果,如(abc | xxx)
可以匹配abc
或者xxx
反向引用,巧用$
分組捕獲
let str = "John Smith";// 交換名字和姓氏
console.log(str.replace(/(john) (smith)/i, '$2, $1')) // Smith, John
三、匹配方法
正則表達式常被用于某些方法,我們可以分成兩類:
- 字符串(str)方法:
match
、matchAll
、search
、replace
、split
- 正則對象下(regexp)的方法:
test
、exec
方法 | 描述 |
---|---|
exec | 一個在字符串中執行查找匹配的RegExp方法,它返回一個數組(未匹配到則返回 null)。 |
test | 一個在字符串中測試是否匹配的RegExp方法,它返回 true 或 false。 |
match | 一個在字符串中執行查找匹配的String方法,它返回一個數組,在未匹配到時會返回 null。 |
matchAll | 一個在字符串中執行查找所有匹配的String方法,它返回一個迭代器(iterator)。 |
search | 一個在字符串中測試匹配的String方法,它返回匹配到的位置索引,或者在失敗時返回-1。 |
replace | 一個在字符串中執行查找匹配的String方法,并且使用替換字符串替換掉匹配到的子字符串。 |
split | 一個使用正則表達式或者一個固定字符串分隔一個字符串,并將分隔后的子字符串存儲到數組中的?String ?方法。 |
str.match(regexp)
str.match(regexp)
?方法在字符串?str
?中找到匹配?regexp
?的字符
如果?regexp
?不帶有?g
?標記,則它以數組的形式返回第一個匹配項,其中包含分組和屬性?index
(匹配項的位置)、input
(輸入字符串,等于?str
)
let str = "I love JavaScript";let result = str.match(/Java(Script)/);console.log( result[0] ); // JavaScript(完全匹配)
console.log( result[1] ); // Script(第一個分組)
console.log( result.length ); // 2// 其他信息:
console.log( result.index ); // 7(匹配位置)
console.log( result.input ); // I love JavaScript(源字符串)
如果?regexp
?帶有?g
?標記,則它將所有匹配項的數組作為字符串返回,而不包含分組和其他詳細信息
let str = "I love JavaScript";let result = str.match(/Java(Script)/g);console.log( result[0] ); // JavaScript
console.log( result.length ); // 1
如果沒有匹配項,則無論是否帶有標記?g
?,都將返回?null
let str = "I love JavaScript";let result = str.match(/HTML/);console.log(result); // null
str.matchAll(regexp)
返回一個包含所有匹配正則表達式的結果及分組捕獲組的迭代器
const regexp = /t(e)(st(\d?))/g;
const str = 'test1test2';const array = [...str.matchAll(regexp)];console.log(array[0]);
// expected output: Array ["test1", "e", "st1", "1"]console.log(array[1]);
// expected output: Array ["test2", "e", "st2", "2"]
str.search(regexp)
返回第一個匹配項的位置,如果未找到,則返回?-1
let str = "A drop of ink may make a million think";console.log( str.search( /ink/i ) ); // 10(第一個匹配位置)
這里需要注意的是,search
?僅查找第一個匹配項
str.replace(regexp)
替換與正則表達式匹配的子串,并返回替換后的字符串。在不設置全局匹配g
的時候,只替換第一個匹配成功的字符串片段
const reg1=/javascript/i;
const reg2=/javascript/ig;
console.log('hello Javascript Javascript Javascript'.replace(reg1,'js'));
//hello js Javascript Javascript
console.log('hello Javascript Javascript Javascript'.replace(reg2,'js'));
//hello js js js
str.split(regexp)
使用正則表達式(或子字符串)作為分隔符來分割字符串
console.log('12, 34, 56'.split(/,\s*/)) // 數組 ['12', '34', '56']
regexp.exec(str)
regexp.exec(str)
?方法返回字符串?str
?中的?regexp
?匹配項,與以前的方法不同,它是在正則表達式而不是字符串上調用的
根據正則表達式是否帶有標志?g
,它的行為有所不同
如果沒有?g
,那么?regexp.exec(str)
?返回的第一個匹配與?str.match(regexp)
?完全相同
如果有標記?g
,調用?regexp.exec(str)
?會返回第一個匹配項,并將緊隨其后的位置保存在屬性regexp.lastIndex
?中。 下一次同樣的調用會從位置?regexp.lastIndex
?開始搜索,返回下一個匹配項,并將其后的位置保存在?regexp.lastIndex
?中
let str = 'More about JavaScript at https://javascript.info';
let regexp = /javascript/ig;let result;while (result = regexp.exec(str)) {console.log( `Found ${result[0]} at position ${result.index}` );// Found JavaScript at position 11// Found javascript at position 33
}
regexp.test(str)
查找匹配項,然后返回?true/false
?表示是否存在
let str = "I love JavaScript";// 這兩個測試相同
console.log( /love/i.test(str) ); // true
四、應用場景
通過上面的學習,我們對正則表達式有了一定的了解
下面再來看看正則表達式一些案例場景:
驗證QQ合法性(5~15位、全是數字、不以0開頭):
const reg = /^[1-9][0-9]{4,14}$/
const isvalid = patrn.exec(s)
校驗用戶賬號合法性(只能輸入5-20個以字母開頭、可帶數字、“_”、“.”的字串):
var patrn=/^[a-zA-Z]{1}([a-zA-Z0-9]|[._]){4,19}$/;
const isvalid = patrn.exec(s)
將url
參數解析為對象
const protocol = '(?<protocol>https?:)';
const host = '(?<host>(?<hostname>[^/#?:]+)(?::(?<port>\\d+))?)';
const path = '(?<pathname>(?:\\/[^/#?]+)*\\/?)';
const search = '(?<search>(?:\\?[^#]*)?)';
const hash = '(?<hash>(?:#.*)?)';
const reg = new RegExp(`^${protocol}\/\/${host}${path}${search}${hash}$`);
function execURL(url){const result = reg.exec(url);if(result){result.groups.port = result.groups.port || '';return result.groups;}return {protocol:'',host:'',hostname:'',port:'',pathname:'',search:'',hash:'',};
}console.log(execURL('https://localhost:8080/?a=b#xxxx'));
protocol: "https:"
host: "localhost:8080"
hostname: "localhost"
port: "8080"
pathname: "/"
search: "?a=b"
hash: "#xxxx"
再將上面的search
和hash
進行解析
function execUrlParams(str){str = str.replace(/^[#?&]/,'');const result = {};if(!str){ //如果正則可能配到空字符串,極有可能造成死循環,判斷很重要return result; }const reg = /(?:^|&)([^&=]*)=?([^&]*?)(?=&|$)/ylet exec = reg.exec(str);while(exec){result[exec[1]] = exec[2];exec = reg.exec(str);}return result;
}
console.log(execUrlParams('#'));// {}
console.log(execUrlParams('##'));//{'#':''}
console.log(execUrlParams('?q=3606&src=srp')); //{q: "3606", src: "srp"}
console.log(execUrlParams('test=a=b=c&&==&a='));//{test: "a=b=c", "": "=", a: ""}