前言
正規表示式其本身就是一種小型的,高度專業化的程式語言,能夠非常方便的對字串進行處理。
正則語法在各個語言中都是通用的,所以掌握它顯得十分有必要。
建立正則
在Js
中,提供兩種建立正則的方式。
字面量建立
使用//
包裹的字面量建立方式是推薦的作法,但它不能在其中使用變數。
<script> "use strict"; let str = "hello,world"; let reg = /^h\w+,\w+$/; // 建立正則物件 console.log(reg.test(str)); // true </script>
下面嘗試使用 a
變數時將不可以查詢.
<script> "use strict"; let str = "hello,world"; let a = "hello"; console.log(/a/.test(str)); // false </script>
可以使用 eval()
轉換為Js
語法來實現將變數解析到正則中,但是比較麻煩,所以有變數時建議使用下面的建構函式建立方式。
<script> "use strict"; let str = "hello,world"; let a = "hello"; console.log(eval(`/${a}/`).test(str)); // true 驗證字串中是否有hello </script>
建構函式建立
使用建構函式建立物件。
<script> "use strict"; let str = "hello,world"; let reg = new RegExp(/^h\w+,\w+$/) console.log(reg.test(str)); // true </script>
當正則需要動態建立時使用這種方式。
<script> "use strict"; let str = "hello,world"; let a = "hello"; let reg = new RegExp(a); console.log(reg.test(str)); // true </script>
基礎語法
. 萬用字元
代表匹配除\n
外的任意字元。如果想匹配\n
可使用s
模式。
<script> "use strict"; let str = "hello,world\nJavaScript-RegExp"; let reg = /........../g; // 匹配十個除開\n外的任意字元 console.log(str.match(reg)); // (2) ["hello,worl", "JavaScript"] </script>
^ 開始符
代表必須以某個字元開始。
<script> "use strict"; let str = "hello,world\nJavaScript-RegExp"; let reg = /^hello,...../g; // 必須以h開始,後面必須是ello, 然後匹配五個除開\n的任意字元。 console.log(str.match(reg)); // ["hello,world"] </script>
$ 結束符
代表必須以某個字元結束。
<script> "use strict"; let str = "hello,world\nJavaScript-RegExp"; let reg = /Exp$/g; // 必須以p結束,前面兩個字元必須是E與x console.log(str.match(reg)); // ["Exp"] </script>
重複符
* 重複符
代表可以取0到無窮位 (預設貪婪取值,可通過?
取消貪婪模式)。
<script> "use strict"; let str_1 = "hello,world\nJavaScript-RegExp"; let str_2 = "h\np"; let reg = /^h.*\n.*p$/g; // 必須是以h開頭,可以有0個也可以有多個除\n外的任意字元,緊接\n,可以有0個也可以有多個除\n外的任意字元,必須以p結尾。 console.log(str_1.match(reg)); // ["hello,world↵JavaScript-RegExp"] console.log(str_2.match(reg)); // ["h↵p"] 上面條件只有三個是必須的 h開頭,p結束,中間必須有換行\n。所以str_2也能匹配出來 </script>
+ 重複符
代表可以取1到無窮位 (預設貪婪取值,可通過?
取消貪婪模式)。
<script> "use strict"; let str_1 = "hello,world\nJavaScript-RegExp"; let str_2 = "h\np"; let reg = /^h.+\n.+p$/g; // 必須是以h開頭,必須有1個也可以有多個除\n外的任意字元,緊接\n,必須有1個也可以有多個除\n外的任意字元,必須以p結尾。 console.log(str_1.match(reg)); // ["hello,world↵JavaScript-RegExp"] console.log(str_2.match(reg)); // null 不滿足條件,至少有一個 </script>
? 重複符
代表可以取0到1位(預設貪婪取值,可通過?
取消貪婪模式)。
<script> "use strict"; let str_1 = "123456789"; let str_2 = "23456789"; let reg = /^1?23456789$/g; // 可以以1開頭,也可以不以,後面是23456789,必須是9結尾 console.log(str_1.match(reg)); // ["123456789"] console.log(str_2.match(reg)); // ["23456789"] </script>
{n,m} 重複符
代表匹配n
到m
次由前面的正規表示式定義的片段(預設貪婪取值,可通過?
取消貪婪模式)。
<script> "use strict"; let str_1 = "1111111"; let reg = /1{3,4}/g; // 可以是3個1,也可以是4個1 console.log(str_1.match(reg)); // ["1111", "111"] </script>
{n} 精確重複
精確匹配n
個前面的表示式。
<script> "use strict"; let str_1 = "1111111"; let reg = /1{3}/g; // 3個1 console.log(str_1.match(reg)); // ["111", "111"] </script>
取消貪婪
使用?
取消貪婪。
<script> "use strict"; let str_1 = "1111111"; let reg_1 = /1*?/g; // 0個或者多個,取消貪婪後不取 let reg_2 = /1+?/g; // 1個或者多個,取消貪婪後取1個 let reg_3 = /1??/g; // 0個或者1個,取消貪婪後不取 let reg_4 = /1{3,4}?/g; // 3個或者4個,取消貪婪後取3個 console.log(str_1.match(reg_1)); // ["", "", "", "", "", "", "", ""] console.log(str_1.match(reg_2)); // ["1", "1", "1", "1", "1", "1", "1"] console.log(str_1.match(reg_3)); // ["", "", "", "", "", "", "", ""] console.log(str_1.match(reg_4)); // ["111", "111"] </script>
字符集
在字符集中上面的字元均失去原本含義。只有-
^
\
可以在字符集中使用。
[] 字符集
其本身代表或的作用 [ab]
代表a
或者b
。
<script> "use strict"; let str_1 = "1111111"; let str_2 = "2222222"; let reg_1 = /[12]+/g; // 1或者2,取多個 console.log(str_1.match(reg_1)); // ["1111111"] console.log(str_2.match(reg_1)); // ["2222222"] </script>
[-] 區間符
字符集中的 -
號代表可以取從多少到多少區間的值,ASCII
碼排序,比如 [a-z 0-9 A-Z]
就是取全部的英文字母和數字。
<script> "use strict"; let str_1 = "12345abcde"; let reg_1 = /[a-z0-9]+/g; // 字元可以是a-z或者0-9,取多個 console.log(str_1.match(reg_1)); // ["12345abcde"] </script>
[^] 排除符
字符集中的 ^
號代表 非 的作用。比如[^0-9]
就是說這一位數並非數字。
<script> "use strict"; let str_1 = "12345abcde"; let str_2 = "x2345abcde"; let reg_1 = /^[^0-9].+/g; // 不能以0-9開頭,緊跟著取處\n外的任意字元 console.log(str_1.match(reg_1)); // null console.log(str_2.match(reg_1)); // ["x2345abcde"] </script>
[\] 轉義符
除開在字符集中使用還可以在外部使用,它可以使所有具有特殊意義的字元失去特殊意義。並且還可以為特定的字元指定意義。
<script> "use strict"; let str_1 = "\t\n\t\n"; let reg_1 = /[\t\n]+/g; // 取\t或\n console.log(str_1.match(reg_1)); // [" ↵ ↵"] </script>
其他的轉義符會在下面介紹。這裡舉例只代表\
可以在字符集中使用。
\ 轉義符
轉義符除開在字符集中使用,也可以在外部使用。
\d | 匹配任何十進位制數,它相當於在字符集中使用[0-9] |
\D | 匹配任何非十進位制數,它相當於在字符集中使用[^0-9] |
\s | 匹配任何空白字元,它相當於在字符集中使用[\t\n\r\f\v] |
\S | 匹配任何非空白字元,它相當於在字符集中使用[^\t\n\r\f\v] |
\w | 匹配任何字母數字下劃線字元,它相當於在字符集中使用[a-z A-Z 0-9] |
\W | 匹配任何非字母數字下劃線字元,它相當於在字符集中使用[a-z A-Z 0-9] |
\b | 匹配一個特殊字元邊界,比如空格 ,& .# 等(不常用) |
\A | 匹配字串開始(不常用) |
\Z | 匹配字串結束,如果存在換行則只匹配換行前的字元(不常用) |
\z | 匹配字串結束(不常用) |
\G | 匹配最後匹配完成的位置(不常用) |
\n | 匹配一個換行符(不常用) |
\t | 匹配一個製表符(不常用) |
\f | 匹配一個分頁符(不常用) |
| 管道符
相當於 或 請注意與字符集裡的區別。|
符將前後分為兩段,左右看做一個整體,而[]
中的或僅僅代表從眾多選項中取出一個。
<script> "use strict"; let str_1 = "abcdefabcccde"; let reg_1 = /abc|def/g; // 取abc或者def console.log(str_1.match(reg_1)); // ["abc", "def", "abc"] </script>
分組
() 分組符
將多個元素字元看出一個元素字元進行匹配。
<script> "use strict"; let str_1 = "asdfghjkl"; let str_2 = "asbfghjkl"; let reg_1 = /^(asd)\w+l$/g; // 必須以asd開頭,必須以l結尾 console.log(str_1.match(reg_1)); // ["asdfghjkl"] console.log(str_2.match(reg_1)); // null </script>
分組別名
組別名使用 (?<別名>匹配規則)
形式定義。在使用match
檢測時需要取消g
模式的全域性匹配。
<script> "use strict"; let str_1 = "http://www.google.com/"; let reg_1 = /^https?:\/\/w{3}\.(?<name>\w+)\.(com|cn|org|hk)/; console.log(str_1.match(reg_1)); // ["http://www.google.com", "google", "com", index: 0, input: "http://www.google.com/", groups: {name: "google"}] console.dir(str_1.match(reg_1).groups.name); // google </script>
分組引用
每一個分組都有一個編號,如1,2,3,4,5。
\num
在匹配時引用原子組, $num
指在替換時使用匹配的組資料。
如下所示,將所有的<h1-6>
標籤替換為<p>
標籤,使用編號替換。
<script> "use strict"; let str_1 = ` <h1>hello,world</h1> <h2>hello,JavaScript</h2> <h3>PHP,no.1!!!</h3> `; let reg = /<(?<grade>h[1-6])>(?<content>[\s\S]*?)\/\1/gi; // 最後的\1代表引用第一個分組的匹配規則,即grade組 [\s\S]代表匹配任意 let new_str = str_1.replace(reg,`<p>$2</p>`); // $2 代表拿到第二個分組的內容,即content分組。 console.log(new_str); // <p>hello,world<</p>> // <p>hello,JavaScript<</p>> // <p>PHP,no.1!!!<</p>> </script>
也可以使用別名替換。$<別名>
。
let new_str = str_1.replace(reg,`<p>$<content></p>`); // 拿到content分組
console.log(new_str);
記錄取消
通常情況下,我們的分組會記錄編號方便後面使用。
如果一個分組的內容編號不想被記錄,可使用(?:)
進行處理。
<script> "use strict"; let str_1 = "123,abc,456"; let reg_1 = /(?:\d+),([a-z]+),(\w+)/; let reg_2 = /(\d+),([a-z]+),(\w+)/; console.log(str_1.match(reg_1)); // (3) ["123,abc,456", "abc", "456", index: 0, input: "123,abc,456", groups: undefined] console.log(str_1.match(reg_2)); // (4) ["123,abc,456", "123", "abc", "456", index: 0, input: "123,abc,456", groups: undefined] // 可以看到。reg_2的長度多了一位,記錄了第一個分組。 </script>
斷言匹配
斷言雖然寫在擴號中但它不是組,所以不會在匹配結果中儲存,可以將斷言理解為正則中的條件。
(?=exp)
零寬先行斷言 ?=exp
匹配後面為 exp
的內容。
<script> "use strict"; let str_1 = "hello,JavaScript"; let reg_1 = /\w+(?=,JavaScript)/g; // 匹配出後面是,JavaScript的內容 console.log(str_1.match(reg_1)); // ["hello"] </script>
(?<=exp)
零寬後行斷言 ?<=exp
匹配前面為 exp
的內容。
<script> "use strict"; let str_1 = "hello,JavaScript"; let reg_1 = /(?<=hello,)\w+/g; // 匹配出前面是hello,的內容 console.log(str_1.match(reg_1)); // ["JavaScript"] </script>
(?!exp)
零寬負向先行斷言 後面不能出現 exp
指定的內容。
<script> "use strict"; let str_1 = "_123"; let str_2 = "yun23"; let str_3 = "123"; let reg_1 = /^(?!_)[\w]+/g; // 匹配開始不能是下劃線的 console.log(str_1.match(reg_1)); // null console.log(str_2.match(reg_1)); // ["yun23"] console.log(str_3.match(reg_1)); // ["123"] </script>
(?<!exp)
零寬負向後行斷言 前面不能出現exp
指定的內容
<script> "use strict"; let str_1 = "abc123 456"; let reg_1 = /(?<!\s+)\d{3}/g; // 前面不能是空格的三位數字 console.log(str_1.match(reg_1)); // ["123"] </script>
匹配模式
正規表示式在執行時會按他們的預設執行方式進行,但有時候預設的處理方式總不能滿足我們的需求,所以可以使用模式修正符更改預設方式。
修飾符 | 說明 |
---|---|
i | 不區分大小寫字母的匹配 |
g | 全域性搜尋所有匹配內容 |
m | 視為多行 |
s | 視為單行忽略換行符,使用. 可以匹配所有字元 |
y | 從 regexp.lastIndex 開始匹配 |
u | 正確處理四個字元的 UTF-16 編碼 |
i
i
模式匹配時不區分大小寫。
<script> "use strict"; let str_1 = "HELLO,WORLD"; let reg_1 = /hello,world/i; console.log(str_1.match(reg_1)); // ["HELLO,WORLD", index: 0, input: "HELLO,WORLD", groups: undefined] </script>
g
g
模式不會在第一次匹配成功後就停止,而是繼續向後匹配,直到匹配完成。
<script> "use strict"; let str_1 = "HELLO,WORLD"; let reg_1 = /./g; console.log(str_1.match(reg_1)); // (11) ["H", "E", "L", "L", "O", ",", "W", "O", "R", "L", "D"] </script>
m
m
模式會將每一行單獨匹配,用於將內容視為多行匹配,主要是對 ^
和 $
的修飾
<script> "use strict"; let str_1 = ` # 1.HTML5 # # 2.CSS # # 3.JavaScript # `; let reg_1 =/^\s+# \d\.\w+ #$/gm; // g模式,全域性,m模式,多行。每一行必須是多個空格開頭,#號結尾。 console.log(str_1.match(reg_1)); // ["↵↵ # 1.HTML5 #", " # 2.CSS #", " # 3.JavaScript #"] </script>
s
s
模式將多行以一行匹配,忽略換行符\n
。這代表使用.
可匹配到任意字元。
<script> "use strict"; let str_1 = `123\n456\n789`; let reg_1 =/.*/gs; console.log(str_1.match(reg_1)); // ["123↵456↵789", ""] </script>
u
每個字元都有屬性,如L
屬性表示是字母,P
表示標點符號,需要結合 u
模式才有效。其他屬性簡寫可以訪問
如果是一些特殊的生僻字元,那麼它的位元組寬度可能是4位元組或更多。此時就無法正確解釋出來,使用u
模式可解決該問題。
<script> "use strict"; let str_1 = "??"; let reg_1 =/??/g; let reg_2 =/??/gu; console.log(str_1.match(reg_1)); // 結果為亂字元"�" console.log(str_1.match(reg_1)); // ["??"] </script>
字元也有unicode
文字系統屬性 Script=文字系統
,下面是使用 \p{sc=Han}
獲取中文字元 han
為中文系統,其他語言請檢視
<script> "use strict"; let str_1 = "雲崖先生"; let reg_1 = /\p{sc=Han}+/gu; console.log(str_1.match(reg_1)); // ["雲崖先生"] </script>
lastIndex
RegExp
物件lastIndex
屬性可以返回或者設定正規表示式開始匹配的位置。
必須結合
g
修飾符使用對
exec
方法有效匹配完成時,
lastIndex
會被重置為0
<script> "use strict"; let str_1 = "Hello,My name is YunYa,YunYa age is 19"; let reg_1 = /YunYa.+/g; reg_1.lastIndex = 23; // 從索引23處開始匹配。 console.log(reg_1.exec(str_1)); // ["YunYa age is 19", index: 23, input: "Hello,My name is YunYa,YunYa age is 19", groups: undefined] </script>
y
g
模式無論成功與否都會一直向後匹配,直到lastIndex
等於length
。
而y
模式也是一直向後匹配,但是隻要匹配不成功就會停止。
<script> "use strict"; let str_1 = "1211111"; let reg_1 = /1/g; let reg_2 = /1/y; console.log(reg_1.exec(str_1)); // ["1", index: 0, input: "1211111", groups: undefined] console.log(reg_2.exec(str_1)); // ["1", index: 0, input: "1211111", groups: undefined] console.log(reg_1.lastIndex); // 1 console.log(reg_2.lastIndex); // 1 console.log(reg_1.exec(str_1)); // ["1", index: 2, input: "1211111", groups: undefined] console.log(reg_2.exec(str_1)); // null console.log(reg_1.lastIndex); // 3 沒找到,g模式繼續 console.log(reg_2.lastIndex); // 0 沒找到,y模式歸零 </script>
字串方法
以下字串方法都可以和正則搭配使用。
search
search()
方法用於檢索字串中指定的子字串的索引值,也可以使用正規表示式搜尋,返回值為索引位置
<script> "use strict"; let str_1 = "YunYaSir c2323182108@gmail.com"; let reg_1 = /c\d+@\w+.?\w+?\.com/; console.log(str_1.search(reg_1)); // 9 </script>
match
match()
方法可以返回出匹配到的子字串。
<script> "use strict"; let str_1 = "YunYaSir c2323182108@gmail.com"; let reg_1 = /c\d+@\w+.?\w+?\.com/; console.log(str_1.match(reg_1)); // ["c2323182108@gmail.com", index: 9, input: "YunYaSir c2323182108@gmail.com", groups: undefined] // 查詢到的內容 索引位置 被查詢的字串 分組資訊 </script>
如果使用g
模式,返回的內容沒那麼詳細了。
<script> "use strict"; let str_1 = "YunYaSir c2323182108@gmail.com"; let reg_1 = /c\d+@\w+.?\w+?\.com/g; console.log(str_1.match(reg_1)); // ["c2323182108@gmail.com"] </script>
matchAll
match()
如果不是在g
模式下,那麼只會檢索一次。
而matchAll()
是全域性檢索,返回一個可迭代物件。
<script> "use strict"; let str_1 = "YunYaSir c2323182108@gmail.com c238923874@qq.com"; let reg_1 = /c\d+@\w+.?\w+?\.com/g; let res = str_1.matchAll(reg_1); for (const iterator of res) { console.log(iterator); } </script>
split
用於使用字串或正規表示式分隔字串。
如下示例,時間的分隔符不確定是那個,此時可以使用正則匹配。
<script> "use strict"; let str_1 = "2020-08/09"; let reg_1 = /[-/]/g; console.log(str_1.split(reg_1)); // (3) ["2020", "08", "09"] </script>
replace
replace()
方法不僅可以執行基本字元替換,也可以進行正則替換,下面替換日期連線符
<script> "use strict"; let str_1 = "2020-08/09"; let reg_1 = /[-/]/g; console.log(str_1.replace(reg_1,"-")); // 2020-08-09 </script>
字串替換
替換字串可以插入下面的特殊變數名:
變數 | 說明 |
---|---|
$$ |
插入一個 "$"。 |
$& |
插入匹配的子串。常用 |
$` |
插入當前匹配的子串左邊的內容。 |
$' |
插入當前匹配的子串右邊的內容。 |
$n |
假如第一個引數是 RegExp 物件,並且 n 是個小於100的非負整數,那麼插入第 n 個括號匹配的字串。提示:索引是從1開始 |
將百度一下四個文字加上鍊接:
<body> <div>百度一下,你就知道</div> </body> <script> "use strict"; let div = document.querySelector("div"); div.innerHTML = div.innerHTML.replace("百度一下","<a href='http://www.baidu.com'>$&</a>") </script>
回撥函式
replace()
支援回撥函式操作,用於處理複雜的替換邏輯。
變數名 | 代表的值 |
---|---|
match | 匹配的子串。(對應於上述的$&。) |
p1,p2, ... | 假如replace()方法的第一個引數是一個 RegExp 物件,則代表第n個括號匹配的字串。(對應於上述的$1,$2等。)例如,如果是用 /(\a+)(\b+)/ 這個來匹配,p1 就是匹配的 \a+ ,p2 就是匹配的 \b+ 。 |
offset | 匹配到的子字串在原字串中的偏移量。(比如,如果原字串是 'abcd' ,匹配到的子字串是 'bc' ,那麼這個引數將會是 1) |
string | 被匹配的原字串。 |
NamedCaptureGroup | 命名捕獲組匹配的物件 |
使用回撥函式將百度一下四個字加上鍊接:
<body> <div>百度一下,你就知道</div> </body> <script> "use strict"; let div = document.querySelector("div"); div.innerHTML = div.innerHTML.replace("百度一下",(search,pos,source)=> `<a href='http://www.baidu.com'>${search}</a>`) </script>
正則方法
下面是 RegExp
正則物件提供的操作方法
test
返回布林值,是否驗證成功。
檢測輸入的郵箱是否合法:
<body> <input type="text" name="email" /> </body> <script> let email = document.querySelector(`[name="email"]`); email.addEventListener("keyup", e => { console.log(/^\w+@\w+\.\w+$/.test(e.target.value)); }); </script>
exec
不使用 g
修飾符時與 match
方法使用相似,使用 g
修飾符後可以迴圈呼叫直到全部匹配完。
使用
g
修飾符多次操作時使用同一個正則,即把正則定義為變數使用使用
g
修飾符最後匹配不到時返回null
計算JavaScript
共出現了幾次。
<body> <div>JavaScript的事件迴圈模型與許多其他語言不同的一個非常有趣的特性是,它永不阻塞。JavaScript非常優秀!</div> </body> <script> "use strict"; let txt = document.querySelector("div").innerHTML; let reg = /(?<tag>JavaScript)/gi; let num = 0; while (reg.exec(txt)) { num++; } console.log(`JavaScript共出現:${num}次。`); </script>