你真的懂JavaScript的正則嗎?

本文內容主要出處爲《JavaScript權威指南》(第六版),筆者只是在搬磚的同時整理思路,有誤望及時指出,感謝!javascript

定義正則表達式

概述

對於正則表達式的概念咱們就很少費口舌了...
在JavaScript中使用正則表達式進行模式匹配離不開RegExp對象,建立正則對象有兩種方式
1.正則表達式直接量(包含在一對/之間的字符)html

var reg = /java/;
reg.test('java'); // true複製代碼

2.new RegExp()java

var reg = new RegExp('java');
reg.test('java'); // true複製代碼

JavaScript也賦予了String對象進行模式匹配的方法,可是使用這些方法的時候一樣離不開RegExp
例如:c++

var str = 'java';
str.match(/java/); // /java/爲正則直接量複製代碼

StringRegExp 如何進行正則匹配,有哪些方法,會在下面兩節講解,這一節(定義正則表達式),主要講述如何定義正則表達式(本節會用到RegExptestexec 方法,如若不瞭解,能夠與最後一節結合來理解)正則表達式

正則——直接字符量

直接字符量表示字符在正則表達式中的表達形式。特殊字符需\轉義數組

字母、數字 -> 自身
\o -> NUL字符(\u0000)
\t -> 製表符(\u0009)
\n -> 換行符(\u000A)
\v -> 垂直製表符(\u000B)
\f -> 換頁符(\u000C)
\r -> 回車符(\u000D)
...複製代碼

正則——字符類

將字符量放入 [] 中就成了字符類,字符類匹配它包含的任意一個字符函數

[abc] // 表示a 或者b 或者c
[^abc] // ^在這裏表示取反,除了a、b、c以外的全部字符
[a-z] //-表示鏈接,從a到z的任意字符複製代碼

由上面咱們能夠知道,[0-9]表示任意數字,像這種經常使用的字符類,JavaScript給他們制訂了本身的特殊轉義字符。ui

. // 除換行符與其餘Unicode行終止符之外的任意字符
\w // 等價於[a-zA-Z0-9_],大小寫字母、數字、下劃線63字符中任意一個
\W // 等價於[^a-zA-Z0-9_]
\s // 任何Unicode空白符
\S // 任何Unicode非空白符
\d // 等價於[0-9]
\D // 等價於[^0-9]
[\b] // \b放入[]中標識退格直接量複製代碼

正則——重複

描述相同字符,屢次出現spa

{n, m} // 最少重複n次,最多重複m次
{n, } // 至少重複n次
{n} //重複n次
? // 等價於 {0, 1}
+ // 等價於 {1,}
* // 等價於 {0,}複製代碼

例如:3d

var reg = new RegExp('a{2,}');
var str = 'aaa';
var str2 = 'a';
reg.test(str); // true
reg.test(str2); // false複製代碼

在這裏會多出一個概念:非貪婪重複
在上述例子中,reg.test(str) === true
咱們用reg.exec(str) 獲取匹配結果會發現 結果爲'aaa'
若是咱們選擇使用非貪婪重複

var reg = new RegExp('a{2,}?');
var str = 'aaa';
reg.exec(str);複製代碼

這時候結果爲 'aa',實現非貪婪重複很簡單,在重複後面添加?便可,這時候,正則表達式會盡量少的去匹配重複。

{n, m} -> {n, m}?
{n, } -> {n,}?
{n} -> {n}?
? -> ??
+ -> +?
* -> *?複製代碼

選擇

| 能夠分割用於選擇的字符,優先級從左向右

ab|cd|ef // 表示 ab 或者 cd 或者 ef複製代碼

子模式

() 在包裹子表達式同時將其定義爲子模式
咱們能夠經過 \index 這種寫法在同一個正則表達式中調用子模式, index表示子模式的索引,從1開始。

var reg1 = /(java)script and \1/;
var reg2 = /javascript and java/;
// reg1 與 reg2 是兩個基本等價的正則直接量
var str = 'javascript and java';
reg1.test(str); // true
reg2.test(str); // true複製代碼

子模式還有助於咱們抽取子表達式匹配結果
把上述例子改成用exec方法而且打印

var reg1 = /(java)script and \1/;
var reg2 = /javascript and java/;
var str = 'javascript and java';
console.log(reg1.exec(str));
console.log(reg2.exec(str));複製代碼

輸出結果爲:


能夠看到,當存在子模式時候,結果集會添加其子模式匹配結果,從中咱們也能夠看出,爲何子模式 index的索引會從1開始,由於0是完整的正則匹配結果。

固然,JavaScript容許咱們在使用子表達式的時候不生成子模式
使用(?: )來包裹子表達式

var reg = /(?:java)script and java/;複製代碼

此時咱們沒法經過\1找到其子模式,也沒法獲取其子模式的匹配結果。

指定匹配位置

^ // 字符串開始位置(在字符類中表示取反)
$ // 字符串的結束位置
\b // 單詞邊界,也就是\w與\W的邊界
(?=p) // 要求字符串與p匹配,可是結果集並不包含匹配p的字符
(?!p) // 要求字符串不與p匹配複製代碼

^ 與 $

/^javascript/ // 字符串以javascript開始
/javascript$/ // 字符串以javascript結束複製代碼

\b

var reg = /\bjava\b/;
var str1 = 'java';
var str2 ='javascript';
var str3 = 'java c++';
var str4 = 'html java c++';
reg.test(str1); // true
reg.test(str2); // false
reg.test(str3); // true
reg.test(str4); // true
在這裏 \b 匹配非\w字符,包括字符串起始與結束。
\B與之相反,匹配非單詞邊界處複製代碼

(?=)

var reg = /java(?=script)/;
var str = 'java';
var str1 = 'javascript';
reg.exec(str); // 匹配失敗 , 由於不包含script
reg.exec(str1); // 此時匹配成公,可是匹配結果並不包含script複製代碼

輸出結果爲:


(?!)

var reg = /java(?!script)/;
var str = 'javaee';
var str1 = 'javascript';
reg.exec(str); // 匹配成功,匹配結果爲java
reg.exec(str1); // 匹配失敗,由於包含script複製代碼

修飾符

i // 不區分大小寫
m // 匹配多行(使用^ $指定起止時候能通融\n換行)
g // 匹配成功第一處,並不會繼續中止,會繼續尋找全部匹配複製代碼

經過直接量建立正則對象添加修飾符: /java/gim (使用多個修飾詞直接並列)
經過構造函數建立正則對象添加修飾符: new RegExp(reg , 'gim');

經過String的模式匹配

String對象提供四種方法用於正則匹配。

search()

str.search(reg)
匹配成功返回起始位置,失敗返回-1,在search方法中修飾詞g不生效

var str = 'hello java';
str.search(/java/); // 6
str.search(/^java/); // -1複製代碼

match()

str.match(reg)
匹配失敗返回null,匹配成功返回的是一個由匹配結果組成的數組。若是該正則 表達式設置了修飾符g,則該方法返回的數組包含字符串中的全部匹配結果。

var str = 'hello java and javascript';
str.match(/java/); 
str.match(/java/g);複製代碼

輸出結果爲:

replace()

兩種調用方式,第二個參數不一樣

  • str.replace(reg , replaceStr)

    var str = 'javaee javaee';
    // str1 = 'javascript javaee'
    var str1 = str.replace(/e{2}/ , 'script'); 
    // str2 = 'javascript javascript' 修飾符g表示全局替換
    var str2 = str.replace(/e{2}/g , 'script'); 
    // 補充知識點:str 依然是 javaee ,至於緣由,簡單說就是字符串直接量不可改變,字符串全部的有關於值的改變的方法都是return新值。複製代碼

    第二個參數replaceStr,用於替換的字符串有一些特殊的寫法

    var reg = /"([^"]*)"/g; // 匹配 "" 間的內容,且內容不包含"
    var str = '"java","c++" and "html"';
    var str1 = str.replace(reg , '「$1」');
    console.log(str1) // 「java」,「c++」 and 「html」複製代碼

    此時,$1表示子模式([^"]*)匹配的結果集, 與咱們上一節定義正則表達式中的調用本身的子模式\1相仿。
    一樣,在此處$還有其餘幾種用法

    $index // 就是上述例子中的$1
    $& // 表示原字符串 -> "java","c++" and "html"
    $` // 匹配字符串的左側值,在上述例子中匹配成功三次,分別爲: 空值 、 "java", 、"java","c++" and $' // 匹配字符串的右側值,在上述例子中匹配成功三次,分別爲: ,"c++" and "html" 、 and "html" 、空值 $$ // 字符常量$複製代碼
  • str.replace(reg , function)

    var reg = /"([^"]*)"/g; // 匹配 "" 間的內容,且內容不包含"
    var str = '"java","c++" and "html"';
    var str1 = str.replace(reg , function (...arr) {
      console.log(arr)
    });複製代碼

    輸出結果爲:

    匹配成功了三次,因此輸出了三次arr數組,這個數組裏面的元素分別爲:
    0: 匹配結果
    ...: 若存在子模式,這裏爲子模式匹配結果
    last - 1: 索引位置
    last: 原字符串

    咱們能夠根據本身想要的結果,動態替換內容,經過return將結果替換到新的字符串中。

    var reg = /"([^"]*)"/g; // 匹配 "" 間的內容,且內容不包含"
     var str = '"java","c++" and "html"';
     var str1 = str.replace(reg , function (...arr) {
      return `「${arr[1]}」`
     });
     console.log(str1) // 「java」,「c++」 and 「html」複製代碼

    split()

    • str.split(分隔符)
      根據分隔符分割返回新數組
    • str.split(reg)
      根據正則分割返回新數組
      var str = 'a,b-c,e,f-g';
      var arr = str.split(/[,-]/);
      console.log(arr) // ['a','b','c','d','e','f','g']複製代碼

經過RegExp的模式匹配

構造函數

var reg = new RegExp('\\w'); // 經過正則表達式字符串
var reg1 = new RegExp(/\w/); // 經過正則表達式直接量
var reg2 = new RegExp(reg , 'gim'); // 第二個參數爲修飾符複製代碼

屬性

  • source: String 正則表達式文本值
  • global: Boolean 是否攜帶全局修飾符g
  • ignoreCase:Boolean 是否攜帶忽略大小寫修飾符i
  • multiline:Boolean 是否攜帶匹配多行修飾符m
  • lastIndex: Number 若是global === true , 那麼這個參數記錄每次匹配後的索引位置,下面的testexec方法會用到

方法

  • reg.exec(str)
    若是匹配失敗,返回null,匹配成功,返回匹配結果,每次執行僅返回一個匹配結果,若global === true,每次匹配成功後,會把lastIndex 屬性設置爲緊挨着 匹配子串的字符位置。再次調用此方法,會從當前位置開始匹配(當咱們使用同一個RegExp匹配新的字符串的時候,最好把lastIndex屬性設置爲0)
    var reg = new RegExp('java' , 'g');
    var str = 'javascript java javaee';
    var result = reg.exec(str);
    while (result) {
      console.log(result)
      console.log(`lastIndex = ${reg.lastIndex}`)
      result = reg.exec(str);
    }複製代碼
    輸出結果爲:

當咱們經過正則表達式直接量來調用進行正則運算的時候,並不會出現這種狀況,那是由於在ES5中,每次經過直接量進行正則運算,JavaScript都會生成新的RegExp對象。

  • reg.test(str)
    test方法與exec基本等價,不一樣的是他們的返回值,test比較簡單粗暴,當exec返回null時候,它返回false,其餘狀況返回true
相關文章
相關標籤/搜索