<li id="2aw4k"></li>
  • <div id="2aw4k"><tr id="2aw4k"></tr></div>
  • <div id="2aw4k"><tr id="2aw4k"></tr></div>
    <center id="2aw4k"><small id="2aw4k"></small></center><center id="2aw4k"><small id="2aw4k"></small></center>
    首頁»JavaScript»系統認識JavaScript正則表達式

    系統認識JavaScript正則表達式

    來源:唐金健 發布時間:2018-05-27 閱讀次數:

    一、正則表達式簡介

    1、什么是正則表達式

    正則表達式,又稱規則表達式。(英語:Regular Expression,在代碼中常簡寫為regex、regexp或RE),計算機科學的一個概念。正則表達式通常被用來檢索、替換那些符合某個模式(規則)的文本。

    簡單的說,就是按照某種規則去匹配符合條件的字符串。

    2、可視化正則表達式工具

    Regexper:https://regexper.com/

    二、RegExp對象

    實例化RegExp的兩種方式。

    兩種方式定義RegExp對象。

    1、字面量

    let reg = /[a-z]{3}/gmi;
    let reg = /[a-z]{3}/g;
    let reg = /[a-z]{3}/m;
    let reg = /[a-z]{3}/i;

    標志

    • g global 代表全局搜索。如果不添加,搜索到第一個匹配停止。
    • m Multi-Line 代表多行搜索。
    • i ignore case 代表大小寫不敏感,默認大小寫敏感。

    2、構造函數

    let reg = new RegExp('\\bis\\b', 'g');

    因為JavaScript字符串中\屬于特殊字符,需要轉義。

    三、元字符

    把元字符當作轉義字符。

    正則表達式有兩種基本字符類型組成。

    • 原義文本字符
    • 元字符

    1、原義文本字符

    表示原本意義上是什么字符,就是什么字符。

    2、元字符

    是在正則表達式中有特殊含義的非字母字符。
    * + ? $ ^ . | \ ( ) { } [ ]

    字符 含義
    \t 水平制表符
    \v 垂直制表符
    \n 換行符
    \r 回車符
    \0 空字符
    \f 換頁符
    \cX 控制字符,與X對應的控制字符(Ctrl + X)

    類似于轉義字符。

    四、字符類

    表示符合某種特性的字符類別。

    使用元字符[]可以構建一個簡單的類。
    所謂類是指符合某些特性的對象,一個泛指,而不是某個字符。

    例子

    表達式[abc]把字符abc歸為一類,表達式可以匹配這一類中的任意一個字符。

    // replace() 方法用于在字符串中用一些字符替換另一些字符,或替換一個與正則表達式匹配的子串。
    'a1b2c3d4e5'.replace(/[abc]/g, '0');  //010203d4e5

    字符類取反

    我們想要替換不是abc中任意一個字符的字符。

    // 元字符 ^ 創建一個 反向類/負向類
    'abcdefg'.replace(/[^abc]/g, '0');  //abc0000

    五、范圍類

    匹配這一個范圍內的字符。

    如果我們想要匹配數字0-9,那么我們可能會這樣寫[0123456789]
    如果我們想要匹配26個字母,那么我們可能會這樣寫[abcdefghijklmnopqrstuvwxyz]
    這樣略顯麻煩,所以才會有范圍類。

    例子

    // 替換所有數字
    'a1c2d3e4f5'.replace(/[0-9]/g, 'x');  //axcxdxexfx
    // 替換所有小寫字母
    'a1c2d3e4f5'.replace(/[a-z]/g, 'x');  //x1x2x3x4x5
    // []組成的類內部是可以連寫的。替換所有大小寫字母
    'a1C2d3E4f5G6'.replace(/[a-zA-Z]/g, '*');  //*1*2*3*4*5*6

    疑問

    如果我想替換數字,并且連帶-符號也一起替換呢?

    // 替換所有數字和橫杠
    '2018-5-21'.replace(/[0-9-]/g, '*');  //*********

    六、預定義類

    一些已經定義的類,可以直接使用。
    字符 等價類 含義
    . [^\r\n] 除了回車、換行之外的所有字符
    \d [0-9] 數字字符
    \D [^0-9] 非數字字符
    \s [\t\n\x0B\r] 空白符
    \S [^\t\n\x0B\r] 非空白符
    \w [a-zA-Z_0-9] 單詞字符(字母、數字、下劃線)
    \W [^a-zA-Z_0-9] 非單詞字符

    例子

    替換一個 ab + 數字 + 任意字符 的字符串

    // 寫法1
    'ab0c'.replace(/ab[0-9][^\r\n]/g, 'TangJinJian');  //TangJianJian
    // 寫法2
    'ab0c'.replace(/ab\d./g, 'TangJinJian');  //TangJianJian

    七、單詞邊界

    字符 含義
    ^ 以xxx開始(不在中括號內時的含義)
    $ 以xxx結束
    \b 單詞邊界
    \B 非單詞邊界

    例子

    我想替換的字符串,屬于那種只在開頭出現的。

    'YuYan is a boy, YuYan'.replace(/^YuYan/g, 'TangJinJian');  //TangJinJian is a boy, YuYan

    我想替換的字符串,屬于那種只在結尾出現的。

    'YuYan is a boy, YuYan'.replace(/YuYan$/g, 'TangJinJian');  //YuYan is a boy, TangJinJian

    單詞邊界例子。

    // 替換所有is為0
    'This is a man'.replace(/is/g, '0');  //Th0 0 a man
    // 替換所有is前面帶有單詞邊界的字符串
    'This is a man'.replace(/\bis/g, '0');  //This 0 a man
    // 替換所有is前面沒有單詞邊界的字符串
    'This is a man'.replace(/\Bis\b/g, '0');  //Th0 is a man

    八、量詞

    用來處理連續出現的字符串。
    字符 含義
    ? 出現零次或一次(最多出現一次)
    + 出現一次或多次(至少出現一次)
    * 出現零次或多次(任意次)
    {n} 出現n次
    {n,m} 出現n到m次
    {n,} 至少出現n次

    我想替換字符串中連續出現10次的數字為*

    '1234567890abcd'.replace(/\d{10}/, '*');  //*abcd

    我想替換字符串中的QQ號碼。

    '我的QQ是:10000'.replace(/[1-9][0-9]{4,}/, '19216811');  //我的QQ是:19216811

    九、貪婪模式

    盡可能多的匹配。

    有這樣的一種場景下的正則表達式,/\d{3,6}/該替換3個數字還是6個數字呢,4、5個數字?

    // 貪婪模式會盡可能的往多的方面去匹配
    '123456789'.replace(/\d{3,6}/, 'x');  //x789
    '123456789'.replace(/\d+/, 'x');  //x
    '123456789'.replace(/\d{3,}/, 'x');  //x

    十、非貪婪模式

    盡可能少的匹配。

    如果我們想要最低限度的替換呢?

    // 非貪婪模式使用 ? 盡可能的往少的方面去匹配
    '12345678'.replace(/\d{3,6}?/g, 'x');  //xx78
    '123456789'.replace(/\d{3,6}?/g, 'x');  //xxx

    因為有g標志,會匹配這段字符串里所有符合規則的字符串。
    第一個規則/\d{3,6}?/g12345678中有兩個符合條件的字符串,是123456。所以替換結果是xx78
    第二個規則/\d{3,6}?/g123456789中有三個符合條件的字符串,是123456789。所以替換結果是xxx

    十一、分組

    括號里的一些規則,分為一組。

    我想替換連續出現3次的字母數字

    //沒有分組的情況下,后面的量詞,只是表示匹配3次數字。
    'a1b2d3c4'.replace(/[a-z]\d{3}/g, '*');  //a1b2d3c4
    //有分組的情況下,分組后面的量詞,表示符合這個分組里規則的字符串,匹配3次。
    'a1b2d3c4'.replace(/([a-z]\d){3}/g, '*');  //*c4

    1、或

    分組里有兩種規則,只要滿足其中一種即可匹配。

    //我想把ijaxxy和ijcdxy都替換成*
    'ijabxyijcdxy'.replace(/ij(ab|cd)xy/g, '*');  //**

    2、反向引用

    可以把分組視為變量,來引用。

    //我想把改變年月日之間的分隔符
    '2018-5-22'.replace(/(\d{4})-(\d{1,2})-(\d{1,2})/g, '$1/$2/$3');  //2018/5/22
    //我想替換日期,并且更改順序
    '2018-5-22'.replace(/(\d{4})-(\d{1,2})-(\d{1,2})/g, '$2/$3/$1');  //5/22/2018

    3、忽略分組

    忽略掉分組,不捕獲分組,只需要在分組內加上?:

    // 忽略掉匹配年的分組后,匹配月的分組變成了$1,日的分組變成了$2
    '2018-5-22'.replace(/(?:\d{4})-(\d{1,2})-(\d{1,2})/g, '$1/$2/$3');  //5/22/$3

    十二、前瞻

    正則表達式從文本頭部向尾部開始解析,文本尾部方向,稱為“前”。
    前瞻就是在正在表達式匹配到規則的時候,向前檢查是否符合斷言,后顧/后瞻方向相反。
    JavaScript不支持后顧。
    符合和不符合特定斷言稱為肯定/正向匹配和否定/負向匹配。
    名稱 正則 含義
    正向前瞻 exp(?=assert)  
    負向前瞻 exp(?!assert)  
    正向后顧 exp(?<=assert) JavaScript不支持
    負向后顧 exp(?<!assert) JavaScript不支持

    例子

    有這樣一個單詞字符+數字格式的字符串,只要滿足這種格式,就把其中的單詞字符替換掉。

    'a1b2ccdde3'.replace(/\w(?=\d)/g, '*');  //*1*2ccdd*3

    有這樣一個單詞字符+非數字格式的字符串,只要滿足這種格式,就把前面的單詞字符替換掉。

    'a1b2ccdde3'.replace(/\w(?!\d)/g, '*');  //a*b*****e*

    十三、RegExp對象屬性

    global是否全文搜索,默認false
    ignore case是否大小寫敏感,默認是false
    multiline多行搜索,默認值是false
    lastIndex是當前表達式匹配內容的最后一個字符的下一個位置。
    source正則表達式的文本字符串。

    let reg1 = /\w/;
    let reg2 = /\w/gim;
    
    reg1.global;  //false
    reg1.ignoreCase;  //false
    reg1.multiline;  //false
    
    reg2.global;  //true
    reg2.ignoreCase;  //true
    reg2.multiline;  //true

    十四、RegExp對象方法

    1、RegExp.prototype.test()

    用來查看正則表達式與指定的字符串是否匹配。返回truefalse
    let reg1 = /\w/;
    reg1.test('a');  //true
    reg1.test('*');  //false

    加上g標志之后,會有些區別。

    let reg1 = /\w/g;
    // 第一遍
    reg1.test('ab');  //true
    // 第二遍
    reg1.test('ab');  //true
    // 第三遍
    reg1.test('ab');  //false
    // 第四遍
    reg1.test('ab');  //true
    // 第五遍
    reg1.test('ab');  //true
    // 第六遍
    reg1.test('ab');  //false

    實際上這是因為RegExp.lastIndex。每次匹配到之后,lasgIndex會改變。
    lastIndex是正則表達式的一個可讀可寫的整型屬性,用來指定下一次匹配的起始索引。

    let reg = /\w/g;
    // 每次匹配到,就會把lastIndex指向匹配到的字符串后一個字符的索引。
    while(reg.test('ab')) {
        console.log(reg.lastIndex);
    }
    // 1
    // 2

    reg.lastIndex初始時為0,第一個次匹配到a的時候,reg.lastIndex1。第二次匹配到b的時候,reg.lastIndex2

    let reg = /\w\w/g;
    while(reg.test('ab12cd')) {
      console.log(reg.lastIndex);
    }
    // 2
    // 4
    // 6

    reg.lastIndex初始時為0,第一個次匹配到ab的時候,reg.lastIndex2。第二次匹配到12的時候,reg.lastIndex4。第三次匹配到cd的時候,reg.lastIndex6

    let reg = /\w/g;
    // 匹配不到符合正則的字符串之后,lastIndex會變為0。
    while(reg.test('ab')) {
        console.log(reg.lastIndex);
    }
    console.log(reg.lastIndex);
    reg.test('ab');
    console.log(reg.lastIndex);
    // 1
    // 2
    // 0
    // 1

    所以,這就是為什么reg.test('ab')再多次執行之后,返回值為false的原因了。

    let reg = /\w/g;
    reg.lastIndex = 2;
    reg.test('ab');  //false

    每次匹配的起始位置,是以lastIndex為起始位置的。上述例子,一開始從位置2開始匹配,位置2后面沒有符合正則的字符串,所以為false

    2、RegExp.prototype.exec()

    在一個指定字符串中執行一個搜索匹配。返回一個搜索的結果數組或null

    非全局情況

    let reg = /\d(\w)\d/;
    let ts = '*1a2b3c';
    let ret = reg.exec(ts);  //ret是結果數組
    // reg.lastIndex肯定是0,因為沒有g標志。 沒有g標志的情況下,lastIndex被忽略。
    console.log(reg.lastIndex + '\t' + ret.index + '\t' + ret.toString());
    console.log(ret);
    // 0  1 1a2,a
    // ["1a2", "a"]

    返回數組是有以下元素組成的:

    • 第一個元素是與正則表達式相匹配的文本。
    • 第二個元素是reg對象的第一個子表達式相匹配的文本(如果有的話)。
    • 第二個元素是reg對象的第二個子表達式相匹配的文本(如果有的話),以此類推。
    // 子表達式就是分組。
    let reg = /\d(\w)(\w)(\w)\d/;
    let ts = '*1a2b3c';
    let ret = reg.exec(ts);
    console.log(reg.lastIndex + '\t' + ret.index + '\t' + ret.toString());
    console.log(ret);  //輸出結果數組
    // 0  1 1a2b3,a,2,b
    // ["1a2b3", "a", "2", "b"]

    全局情況

    let reg = /\d(\w)(\w)(\w)\d/g;
    let ts = '*1abc25def3g';
    while(ret = reg.exec(ts)) {
        console.log(reg.lastIndex + '\t' + ret.index + '\t' + ret.toString());
    }
    // 6  1 1abc2,a,b,c
    // 11 6 5def3,d,e,f

    第一次匹配的是1abc21abc2的后一個字符的起始位置是6,所以reg.lastIndex6
    1abc2的第一個字符的起始位置是1,所以ret.index1

    第二次匹配的是5def35def3的后一個字符的起始位置是11,所以reg.lastIndex11
    5def3的第一個字符的起始位置是6,所以ret.index6

    十五、字符串對象方法

    1、String.prototype.search()

    執行正則表達式和String對象之間的一個搜索匹配。
    方法返回第一個匹配項的index,搜索不到返回-1
    不執行全局匹配,忽略g標志,并且總是從字符串的開始進行檢索。

    我想知道Jin字符串的起始位置在哪里。

    'TangJinJian'.search('Jin');  //4
    'TangJinJian'.search(/Jin/);  //4

    search方法,既可以通過字符串,也可以通過正則描述字符串來搜索匹配。

    2、String.prototype.match()

    當一個字符串與一個正則表達式匹配時, match()方法檢索匹配項。
    提供RegExp對象參數是否具有g標志,對結果影響很大。

    非全局調用的情況

    如果RegExp沒有g標志,那么match只能在字符串中,執行一次匹配。
    如果沒有找到任何匹配文本,將返回null
    否則將返回一個數組,其中存放了與它找到的匹配文本有關的信息。

    let reg = /\d(\w)\d/;
    let ts = '*1a2b3c';
    let ret = ts.match(reg);
    console.log(ret.index + '\t' + reg.lastIndex);
    console.log(ret);
    // 1  0
    // ["1a2", "a"]

    非全局情況下和RegExp.prototype.exec()方法的效果是一樣的。

    全局調用的情況

    我想找到所有數字+單詞+數字格式的字符串。

    let reg = /\d(\w)\d/g;
    let ts = '*1a2b3c4e';
    let ret = ts.match(reg);
    console.log(ret.index + '\t' + reg.lastIndex);
    console.log(ret);
    // undefined  0
    // ["1a2", "3c4"]

    全局情況下和RegExp.prototype.exec()方法的區別。在于,沒有了分組信息。
    如果我們不使用到分組信息,那么使用String.prototype.match()方法,效率要高一些。而且不需要寫循環來逐個所有的匹配項獲取。

    3、String.prototype.split()

    使用指定的分隔符字符串將一個String對象分割成字符串數組。
    'a,b,c,d'.split(/,/);  //["a", "b", "c", "d"]
    'a1b2c3d'.split(/\d/);  //["a", "b", "c", "d"]
    'a1b-c|d'.split(/[\d-|]/);  //["a", "b", "c", "d"]

    4、String.prototype.replace()

    返回一個由替換值替換一些或所有匹配的模式后的新字符串。模式可以是一個字符串或者一個正則表達式, 替換值可以是一個字符串或者一個每次匹配都要調用的函數。

    常規用法

    'TangJinJian'.replace('Tang', '');  //JinJian
    'TangJinJian'.replace(/Ji/g, '*');  //Tang*n*an

    以上兩種用法,是最常用的,但是還不能精細化控制。

    精細化用法

    我想要把a1b2c3d4中的數字都加一,變成a2b3c4d5

    'a1b2c3d4'.replace(/\d/g, function(match, index, orgin) {
        console.log(index);
        return parseInt(match) + 1;
    });
    // 1
    // 3
    // 5
    // 7
    // a2b3c4d5

    回調函數有以下參數:

    • match第一個參數。匹配到的字符串。
    • group第二個參數。分組,如果有n個分組,則以此類推n個group參數,下面兩個參數將變為第2+n3+n個參數。沒有分組,則沒有該參數。
    • index第三個參數。匹配到的字符串第一個字符索引位置。
    • orgin第四個參數。源字符串。

    我想把兩個數字之間的字母去掉。

    'a1b2c3d4e5f6'.replace(/(\d)(\w)(\d)/g, function(match, group1, group2, group3, index, orgin) {
      console.log(match);
      return group1 + group3;
    });
    // 1b2
    // 3d4
    // 5f6
    // a12c34e56
    QQ群:WEB開發者官方群(515171538),驗證消息:10000
    微信群:加小編微信 849023636 邀請您加入,驗證消息:10000
    提示:更多精彩內容關注微信公眾號:全棧開發者中心(fsder-com)
    網友評論(共0條評論) 正在載入評論......
    理智評論文明上網,拒絕惡意謾罵 發表評論 / 共0條評論
    登錄會員中心
    大乐透彩票预测
    <li id="2aw4k"></li>
  • <div id="2aw4k"><tr id="2aw4k"></tr></div>
  • <div id="2aw4k"><tr id="2aw4k"></tr></div>
    <center id="2aw4k"><small id="2aw4k"></small></center><center id="2aw4k"><small id="2aw4k"></small></center>
    <li id="2aw4k"></li>
  • <div id="2aw4k"><tr id="2aw4k"></tr></div>
  • <div id="2aw4k"><tr id="2aw4k"></tr></div>
    <center id="2aw4k"><small id="2aw4k"></small></center><center id="2aw4k"><small id="2aw4k"></small></center>