JavaScript RegExp對象

JavaScript RegExp對象

前言

  正則表達式其本身就是一種小型的,高度專業化的編程語言,能夠非常方便的對字符串進行處理。

  正則語法在各個語言中都是通用的,所以掌握它顯得十分有必要。

 

創建正則

  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} 重複符


  代表匹配nm次由前面的正則表達式定義的片段(默認貪婪取值,可通過?取消貪婪模式)。

 

<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 = "//www.google.com/";
​
        let reg_1 = /^https?:\/\/w{3}\.(?<name>\w+)\.(com|cn|org|hk)/; 
​
        console.log(str_1.match(reg_1)); // ["//www.google.com", "google", "com", index: 0, input: "//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 [email protected]";
        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 [email protected]";
        let reg_1 = /c\d+@\w+.?\w+?\.com/;
​
        console.log(str_1.match(reg_1));
​
        // ["[email protected]", index: 9, input: "YunYaSir [email protected]", groups: undefined]
        // 查找到的內容  索引位置  被查找的字符串  分組信息
</script>

 

  如果使用g模式,返回的內容沒那麼詳細了。

<script>"use strict";
​
        let str_1 = "YunYaSir [email protected]";
        let reg_1 = /c\d+@\w+.?\w+?\.com/g;
​
        console.log(str_1.match(reg_1));
​
        // ["[email protected]"]
</script>

 

matchAll


  match()如果不是在g模式下,那麼只會檢索一次。

  matchAll()是全局檢索,返回一個可迭代對象。

 

<script>"use strict";
​
        let str_1 = "YunYaSir [email protected] [email protected]";
        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='//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='//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>