JS-RegExp函數

項目中遇到一些的字符串處理場景:

  1. 對整型金額進行千分位格式化,如:1,000
  2. 表單字段校驗,如姓名只能是中文且長度範圍是[2,4]
  3. 身份證號保留前6後4,中間8位掩碼處理。

對於這些均可以使用正則表達式完成。若是你還不知道該怎麼用,那有必要學習下正則表達式了。javascript

1、RegExp函數

正則表達式專門用於描述字符串的字符組合格式。咱們常常對字符串判斷是否匹配指定的正則表達式,以及對匹配的字符進行操做(如替換,轉換等)。html

1.1 建立正則表達式對象

RegExp用來表示正則表達式。RegExp便是構造函數也是個工廠函數。
建立正則表達式的方式:java

// 字面量方式
/pattern/flags

// 構造函數方式
new RegExp(pattern [, flags])

// 工廠函數方式
RegExp(pattern [, flags])

1.2 exec(String)方法

對指定對字符串進行一次正則匹配操做。若是匹配成功則返回一個數組,不然返回null。
返回的數組:正則表達式

  1. 第一個元素是匹配成功對字符串;
  2. 從第二個元素開始都是匹配的捕獲分組字符串;
  3. 該數組被添加了兩個額外屬性:
    3.1 inputexpress

    表示輸入原始字符串,即exec方法的實參。

    3.2 indexc#

    表示匹配的字符串在輸入參數的下標位置。
// matchs1爲["ab", "b", index: 0, input: "abcabc"]
var matchs1 = /a(b)/.exec('abcabc'); // 捕獲分組

// matchs2爲["ab", index: 0, input: "abcabc"]
var matchs2 = /ab/.exec('abcabc');

1.3 test(String)方法

判斷指定的字符串是否匹配正則表達式。數組

1.4 flags(i,g,m)

控制匹配行爲。安全

1.5 lastIndex屬性

表示正則表達式下次執行匹配操做時字符串下標位置。ruby

var r = /a(b)/g;
console.log(r.lastIndex); // 0
r.test('abcabc'); //true, 從字符串下標0開始匹配
console.log(r.lastIndex); // 2
r.test('abcabc'); //true, 從字符串下標2開始匹配
console.log(r.lastIndex); // 5

注意幾點:函數

  1. 只有指定全局匹配m時,lastIndex纔有效,不然一直爲0;

    var r = /a(b)/; // 沒有指定全局m
    console.log(r.lastIndex); // 0
    r.test('abcabc'); //true, 從字符串下標0開始匹配
    console.log(r.lastIndex); // 0
    r.test('abcabc'); //true, 從字符串下標0開始匹配
    console.log(r.lastIndex); // 0
  2. 每次執行全局模式匹配(經過exec或者test方法)時都會影響lastIndex的值。
    注意下例中屢次調用會出現匹配失敗的狀況:

    var r = /a(b)/g;
    console.log(r.lastIndex); // 0
    r.test('abcabc'); //true, 從字符串下標0開始匹配
    console.log(r.lastIndex); // 2
    r.test('abcabc'); //true, 從字符串下標2開始匹配
    console.log(r.lastIndex); // 5
    r.test('abcabc'); //false, 從字符串下標5開始匹配
    console.log(r.lastIndex); // 0,下次🈶️從頭開始匹配了
  3. lastIndex屬性是可讀寫的。

    var r = /a(b)/g;
    console.log(r.lastIndex); // 0
    r.test('abcabc'); //true, 從字符串下標0開始匹配
    console.log(r.lastIndex); // 2
    r.test('abcabc'); //true, 從字符串下標2開始匹配
    console.log(r.lastIndex); // 5
    r.lastIndex = 0; // 修改成0,下次從頭開始
    r.test('abcabc'); //true, 從字符串下標0開始匹配
    console.log(r.lastIndex); // 0,下次🈶️從頭開始匹配了

2、String中相關的方法

Sting對象的一些方法都接受正則對象的參數:

  1. replace
  2. split
  3. match
  4. search

3、 正則表達式語法

詳細的見參考,這裏羅列了一些筆記,首先是一張正則知識簡圖:

clipboard.png

  1. 元字符做爲通常字符匹配時須要轉移;
  2. 除了能夠匹配字符外,還能夠匹配位置,即圖中【位置匹配】部分;
  3. 量詞

    • 修飾【字符匹配】,【捕獲分組】,【非捕獲分組】,【前瞻】;
    • 不能修飾【位置匹配】(包含後瞻);但能夠包成分組進行匹配。
  4. 【候選】的優先級最低;

3.1 關於【位置匹配】

正則除了能夠匹配字符外還能夠匹配位置,圖中箭頭指向的地方:

clipboard.png
圖片引用《JavaScript正則迷你書》
位置也是有特性的,而且一個位置能夠有多個特性,如字符串abc123, 正則表達式/^/,/\b/, /(?=a)/都匹配最左側的位置。除了常見的位置匹配字符^,$,\b,\B外,前瞻和後瞻也是位置匹配:

模式 名稱 描述
(?=exp) 正向前瞻 匹配exp前面的位置
(?!exp) 負向前瞻 匹配不知足exp前面的位置,即匹配後面不知足expd的位置
(?<=exp) 正向後瞻 匹配exp後面的位置(ES6支持)
(?<!exp) 負向後瞻 匹配不知足exp後面的位置,即匹配前面不是exp的位置(ES6支持)
'abc123'.replace(/(?=1)/g, '#'); // abc#123, 匹配字符1前面的位置
'abc123'.replace(/(?!1)/g, '#'); // #a#b#c1#2#3#, 匹配不是字符1前面的位置,有多個位置符合要求
'abc123'.replace(/(?<=1)/g, '#'); // abc1#23, 匹配字符1後面的位置
'abc123'.replace(/(?<!1)/g, '#'); // #a#b#c#12#3#, 匹配不是字符1後面的位置

3.2 位置匹配總結

  1. 都是0寬度,不影響lastIndex;
  2. 能夠對同一個位置同時進行多個匹配模式,至關於該位置要知足全部的匹配模式。

    /^^hello\b(?!\w)/.test("hello "); // true

    位置匹配^重複匹配一個位置,至關於一個位置匹配;
    位置匹配\b(?!\w)都是對同一個位置進行匹配,字符b後面的位置便是個單詞結尾又是非單詞字符(本例是空格字符)的前面

  3. 密碼規則校驗問題
    密碼字符集通常是有安全要求的,好比:必須包含數字,大小寫字母等。可使用【位置匹配】:

    // 規則1 = 長度6到15位,必須是數字,字母,下劃線,感嘆號,中劃線
    /^[0-9a-zA-Z_!-]{6,15}$/.test('abc123'); // true,很容易實現
    
    // 規則2 = 規則1 + 必須包含大寫字母
    /(?=.*[A-Z])^[0-9a-zA-Z_!-]{6,15}$/.test('abc123'); // false
    /(?=.*[A-Z])^[0-9a-zA-Z_!-]{6,15}$/.test('abC123'); // true
    
    // 規則3 = 規則2 + 必須包含下劃線
    /(?=.*_)(?=.*[A-Z])^[0-9a-zA-Z_!-]{6,15}$/.test('abC123'); // false
    /(?=.*_)(?=.*[A-Z])^[0-9a-zA-Z_!-]{6,15}$/.test('abC123_'); // true

    原理就是經過找知足條件的位置來判斷目標字符串是否符合指定的規則。規則2(規則3同理)的正則表達式至關於對起始位置添加了多個匹配條件。

3.2 回溯

爲了判斷是否匹配完成,進行了一些嘗試。嘗試的反作用就是形成回溯(形成匹配位置倒退的行爲)。
回溯會影響性能,寫正則儘可能規避形成回溯。

4、 項目中的實戰

1. 金額格式化,形如:1,000:

  • 遇到的寫法1
function reverse(str) {
     return str.split('').reverse().join('');
}
function format(num) {
    return reverse(reverse(num + '').replace(/(\d{3})(?!$)/g, '$1,'));
}
format(123); // '123'
format(1234); // '1,234'
format(12345); // '12,345'
format(123456); // '123,456'
  • 遇到的寫法2
function format(num) {
    return (num + '').replace(/(?!^)(?=(\d{3})+$)/g, ',')
}

一個正則搞定!不過也不能否認,複雜的正則讓人難以理解!!!

2. 表單字段校驗,如只能是字母和數字,且長度範圍[6,18]

// 正則表達式使用了i flag
function validate(str) {
    return /^[a-z0-9]{6,18}$/i.test(str);
}

3. 表單字段校驗,如不許許字符重複三次以上

function validate(str) {
    return return /(.)\1{2,}/i.test(str);
}

正則表達式使用了捕獲分組和反向引用

4. 身份證號保留前6後4,中間8位掩碼處理

function mask(idNo) {
    return idNo.replace(/^(\d{6})\d{8}(.+)$/, '$1********$2')
}

5. 判斷一個字符串的全部字符是否都相同

function validate(str) {
    return /^(.)\1*$/.test(str);
}

6. 銀行卡號格式化:每4位添加個空格

function formatId(idNo) {
    return idNo.replace(/(\d{4})(?!$)/g, '$1 '); // 正則相似例1中的*金額格式化*
}

好玩的正則應用場景持續補充ing

參考

  1. MDN RegExp API
  2. 正則語法教程
  3. Online tool to learn, build, and test Regular Expressions
  4. 司徒正美javascript正則表達式 快速入門
  5. 《JavaScript正則迷你書》
相關文章
相關標籤/搜索