JavaScript正則表達式的模式匹配教程,而且附帶充足的實戰代碼

引言

其實我寫這篇文章的話,主要是想本身從新複習一遍正則表達式。咱們也知道正則表達式在不少語言中都是通用的,因此學好這個好處不少。接下來,就跟我一塊兒來學習一下正則表達式,從0到入門吧。javascript

正文

1、正則表達式定義

正則表達式(regular expression)是一個描述字符模式的對象,簡單點來說就是經過正則表達式規定的模式,從一堆字符串中,找到與該模式匹配的字符串,並能夠完成檢索或字符串替換的功能。java

來舉個例子,讓你們更形象地理解正則表達式的做用。python

你去買蘋果,老闆給你隨便拿了幾個,但你以爲他給你挑的蘋果很差,因而你想從中拿掉一些很差的蘋果,再去挑一些好的蘋果,在選以前,你先想好本身挑選蘋果的標準,好比蘋果的紋路要多 、蘋果要很紅 、蘋果不能太大等等,而後再根據你本身定的標準去這麼多蘋果裏挑選到徹底符合你標準的蘋果放進本身的袋子裏,或者是替換掉袋子裏你以爲很差的蘋果。web

但願大家能對正則表達式有個初步的印象。正則表達式

2、正則表達式的使用

在JavaScript中,正則表達式用RegExp對象表示,咱們能夠經過兩種方式建立一個正則表達式對象:express

  1. RegExp直接量
  2. new RegExp()

3、RegExp直接量

let pattern = /javascript/ 這樣雙正斜槓包裹一個匹配模式的寫法就是RegExp直接量,這種方法實際上是new RegExp()的一種能語法糖的寫法。這一部分咱們都用RegExp直接量的方法來說解,在後面咱們會介紹 new RegExp() 的用法數組

(1)正則表達式初體驗

接下來看一個例子,來初次體驗一下正則表達式的使用併發

//RegExp直接量 建立一個字符串的匹配標準
let pattern = /javascript/           
let str = "I love javascript"

str.search(pattern)           //返回 7

我來說一下這段代碼,首先咱們經過兩個正斜槓// 建立了一個正則表達式對象,而後將咱們要匹配的字符串放到這兩個斜槓中,咱們例子中就是將javascript放到兩個斜槓中,意思就是咱們的匹配標準就是:要匹配到javascript這段字符串。而後咱們調用了一個檢索的方法search(),這個方法須要傳入一個正則表達式對象爲參數,根據這個參數去字符串中匹配相應的字符串,若是匹配到了,則返回第一個與之匹配的字符的索引值;若沒匹配到,返回-1。例子中,變量str中有一段字符串爲javascript,因此匹配成功,並返回javascript的開頭字母的索引值,爲7svg

(2)深刻了解正則

剛纔咱們體驗了一下最簡單的正則表達式去匹配字符串。在上一個例子中,咱們將javascript做爲標準去匹配,其實大多數的字符都是按照字面含義去匹配的,意思就是你輸入什麼字符,就去匹配什麼字符,好比/python/ 就是去字符串中匹配 python字符串 、/123/ 就是去匹配 123 字符串函數

可是在正則表達式中,\ 反斜槓有特殊的做用,在一些字符前面加一個反斜槓,能起到轉義的做用。例如 /n/ 是匹配字符串 n 的,可是/\n/中,n的前面加了一個反斜槓,就將其轉義了,這個匹配模式的意思就是去匹配換行符,下面列出一些其餘的轉義字符

字符 匹配
字母和數字字符 自身
\o NUL 字符(\u0000)
\t 製表符(\u0009)
\n 換行符(\u000A)
\v 垂直製表符(\u000B)
\f 換頁符(\u000C)
\r 回車符(\u000D)

在正則表達式中,許多標點符號都具備特殊的含義,它們是:^ $ . * + ? = ! : | \ / ( ) [ ] { } ,當咱們想要匹配這些字符時,也須要在它們前面加上反斜槓 \ ,例如

/*--------------不對小括號進行轉義----------------*/
let pattern = /you(kimy)/
let str = "I love you(kimy)"

str.search(pattern)       //返回 -1 表示未匹配到相應字符

/*--------------對小括號進行轉義-----------------*/
let pattern = /you\(kimy\)/
let str = "I love you(kimy)"

str.search(pattern)       //返回 7 表示匹配成功

爲何這些標點字符須要進行特殊的轉義呢?由於它們有別的用處,咱們接下來會慢慢介紹他們的用處

字符類

將直接量字符單獨放在方括號裏就組成了一個字符類,一個字符類能夠匹配它所包含的任意字符。例如/[abcd]/ 就是匹配到 abcd四個字符中的任意一個即爲匹配成功。若是在方括號裏最前面加上一個 ^ 符號,則表示爲,只要匹配到一個不是方括號裏的字符的字符串即爲匹配成功,例如 /[^abc]/就是匹配到不是 abc 三個字符中的任意一個即爲匹配成功。 字符類還可使用 - 來表示字符的一個範圍,例如 /[a-zA-Z0-9]/表示匹配到任意一個大小寫字母或者數字都爲匹配成功。

在正則表達式中,還給出了一些特殊字符的轉義,咱們來看下列的表格

字符 匹配
[…] 方括號內的任意一個字符
[^…] 不在方括號內的任意一個字符
. 除了換行符和其餘Unicode行終止符以外的任意字符
\w 至關於[a-zA-Z0-9]
\W 至關於[^a-zA-Z0-9]
\s 任何Unicode空白符
\S 任何非Unicode空白符
\d 任何數字,至關於[0-9]
\D 任何非數字,至關於[^0-9]
[\b] 退格直接量

咱們來選取表格中的 \d 來舉個例子

let pattern = /python\d/
let str = "I love python3"

str.search(pattern)   //返回 7

咱們設置的匹配模式是 /python\d/,表示匹配到一個字符串爲python而且後面緊跟一個任意數字便可,因此成功匹配到 str 中的python3字符串

重複

在上一部分,咱們知道字符類都是匹配一個字符,例如 /\d//[0-9]/都是匹配任意一個數字 、/[abcd]/也是匹配一個字符,那若是咱們想要匹配多個字符串豈不是要寫不少遍重複代碼?例如咱們要匹配一個三位數字的字符串,咱們就須要設置這樣一個匹配模式 /\d\d\d/。 其實正則表達式有幾種語法,能夠將該表達方式簡化,咱們來看一下這個表格

字符 匹配
{n,m} 匹配前一項n-m次
{n,} 匹配前一項至少n次
{n} 匹配前一項n次
? 匹配前一項0次或1次,至關於{0,1}
+ 匹配前一項至少一次,至關於{1,}
* 匹配前一項0次或更屢次,至關於{0,}

咱們接下來就利用這些語法進行一下重複操做,例如咱們要匹配一段字符串中的11位數字,咱們能夠這樣寫 /\d{11}/,由於\d表示的是任意數字,在它後面加上一個重複語法,就是重複\d多少次。咱們若是要匹配一個三位的字母而且後面跟上一個一位的可選數字,咱們能夠這樣 /[a-zA-Z]{3}\d?/[a-zA-Z]{3} 表示匹配任意三位字母,\d? 表示匹配數字0次或1次

重複是貪婪的,它們會盡量的多地匹配,咱們稱之爲貪婪的重複,下面來看一個例子

let pattern = /\d{3,10}/
let str = "0123456789"

str.match(pattern)[0]     //返回 0123456789

這裏介紹一個新的匹配方法 match ,它能夠將匹配到的一段字符串放在一個數組裏,若沒匹配到則返回null。 在這個例子中,咱們設置的匹配模式是/\d{3,10}/,表示匹配數字3到10次,由於重複語法默認是貪婪的,它會盡量多地匹配,因此他就匹配了任意數字10次,返回 0123456789

那麼若是咱們如何使他們不貪婪地重複呢?其實很簡單,咱們只須要在重複的語法後面加一個 ? 便可將重複變成非貪婪的,仍是這個例子

let pattern = /\d{3,10}?/
let str = "0123456789"

str.match(pattern)[0]     //返回 012

這是咱們能夠看到,在重複語法 {3,10}後面加上一個 ? 之後,它並無儘量多地匹配了,而是變成了儘量少地匹配,即匹配三次任意數字就結束匹配。

還有其餘的非貪婪重複的語法有: ??+?*? ,大家能夠下去自行測試

選擇

在JavaScript中有一個運算符能夠用在正則表達式中,那就是 | ,它的意思就是或者,例如這個例子 /[a-z]|[0-9]/ 意思就是能夠匹配任意一個a-z的字母,或者也能夠匹配任意一個0-9的數字。

在複雜的例子裏,咱們也能夠這樣使用,先給出需求,匹配一段字符串,它能夠是3位的不區分大小寫的字母,也能夠是4位的數字

let pattern = /[a-zA-Z]{3}|\d{4}/
let str = "Lpyexplore2333"

str.match(pattern)[0]   //返回 Lpy

在這個例子中,咱們匹配的模式是3位的不區分大小寫的字母或者4位數字,可是 str 中既有3位的不區分大小寫的字母,也有4位數字,爲何最後只是返回了Lpy呢? 由於正則的匹配是從字符串的最左邊開始匹配,只要有一個符合匹配模式的就中止匹配。

分組與引用

上面咱們說過,在正則表達式中小括號是有特殊含義的,若是真的想要匹配帶有小括號的字符串,必需要用反斜槓轉移,接下來咱們就來介紹一下 () 小括號的幾種做用。

  1. 做用一: 把匹配模式中的部分項組合成子表達式

相似於這樣 /java(script)?/,這種匹配模式的意思就是,匹配一段爲 java 或者 javascript 的字符串。咱們能夠試一下,若是去掉這個括號會是什麼結果,即 /javascript?/,這種匹配模式的意思就是,匹配一段爲 javascrip 或者 javascript 的字符串。

因此咱們能夠很清楚的知道,() 小括號能夠幫咱們組合一個子表達式,而後將這個子表達式做爲總體,配合 |*?+ 等符號去處理。

  1. 做用二:定義一個子匹配模式,方便獲取子匹配模式匹配到的字符串

在將這個做用前,我仍是再來詳細介紹一下我以前例子中用到的匹配方法 match() 的具體用法。

match() 方法須要傳入一個正則表達式,而後根據這個參數去匹配字符串,最後返回一個數組,數組的第一個元素是該參數匹配到的字符串,數組的第二個元素是該正則表達式中第一個()小括號內匹配到的字符串,數組的第三個元素是該正則表達式中第二個()小括號內匹配到的字符串,這樣以此類推。若沒匹配到就返回null

介紹完 match() 方法的使用之後,咱們來看一個例子

/*---------------------在匹配模式中加小括號--------------*/

let pattern = /java(script\d+)/
let str = "javascript2333"

str.match(pattern)   //返回 ['javascript2333', 'script2333']

/*---------------------不在匹配模式中加小括號--------------*/

let pattern = /javascript\d+/
let str = "javascript2333"

str.match(pattern)   //返回 ['javascript2333']

咱們能夠看到,在匹配模式中加了小括號,最後返回的數組中會額外返回一個元素,用於存放小括號定義的子匹配模式匹配到的字符串。

接下來舉一個實戰中的例子

有這樣一個 url 地址 https://www.baidu.com/s?query=javascript,咱們知道 ? 後面跟的是請求參數,若是咱們想要獲取請求參數 query 的值,也就是 query= 後面的字符串,咱們該如何使用正則表達式去匹配呢?

let pattern = /query=([a-zA-Z]+)/
let str = "https://www.baidu.com/s?query=javascript"

str.match(pattern)  //返回 ['query=javascript', 'javascript']

在這個例子中,咱們很明確的知道咱們只是想獲取 query= 後面的字符串,可是若是咱們直接用這個模式 /query=[a-zA-Z]+/ 去匹配的話,咱們最後只能得到 query=javascript 這樣一整段字符串。因此咱們能夠在咱們可使用小括號來定義一個子匹配模式,這樣在返回的數組中直接獲取小括號匹配返回的值就能夠了。

  1. 做用三:小括號定義的子匹配模式能夠被反斜槓+數字再次引用

其實做用三是在做用二的基礎上的,咱們能夠經過一個反斜槓 \ 加上數字 n來引用該匹配模式中第n個括號定義的子匹配模式,例如 /java(script)\1/,這個意思就是 \1的部分須要匹配的字符串要跟(script) 同樣

let pattern = /java(\d+)\1/
let str = "java123123"

str.match(pattern)    //返回 ['java123123', '123']

在這個例子中,\1(\d+)進行了一次引用,注意是引用,而不是這樣 /java(\d+)(\d+)/。咱們來看一下這二者的區別

/*----------------使用反斜槓加數字引用----------------*/

let pattern = /java(\d+)\1/
let str = "java123321"

str.match(pattern)  //返回 null

/*----------------徹底的重複一遍子匹配模式----------------*/

let pattern = /java(\d+)(\d+)/
let str = "java123321"

str.match(pattern)  //返回 ['java123321', '12332', '1']

經過這兩個例子的對比,咱們能夠發現如下幾點區別:

  1. 子匹配模式必須和反斜槓+數字 匹配到的字符串如出一轍,不然匹配失敗
  2. 兩個相同的子匹配模式則不須要二者匹配到如出一轍的字符串
  3. 反斜槓+數字 雖然是對定義的子匹配模式的引用,但在匹配返回的結果裏,卻不會返回 反斜槓+數字 匹配到的內容

補充:若是咱們用小括號定義的子匹配模式不想被反斜槓+數字引用,咱們能夠在小括號內部的最前面加上 ?:,即這種形式 (?:\d+) ,這樣的話咱們就沒法在後面使用 反斜槓+數字 來引用這個子匹配模式了。

例如:

let pattern = /java(?:script)(\d+)\1/
let str = "javascript1212"

str.match(pattern)      //返回 ['javascript1212', '12']

例子中咱們能夠看到, \1 是對第二個子匹配模式(\d+)進行了引用,其實咱們能夠這樣理解,使用這種形式(?:...)定義的子匹配模式,不會被計入編號中,因此也不會被 反斜槓+數字 引用。

指定匹配位置

在正則表達式中,我能夠利用某些字符,去指定匹配發生的位置。這些字符咱們稱之爲正則表達式的

字符 含義
^ 匹配字符串的開頭
$ 匹配字符串的結尾
\b 匹配一個單詞的邊界
\B 匹配非單詞邊界的位置
(?=p) 零寬正向先行斷言,?=後面的字符都要與p匹配,但不能包括p的那些字符
(?!p) 零寬負向先行斷言,?!後面的字符不與p匹配

咱們來逐個說一下這幾個字符的用法:

  • ^ 符號

^ 這個符號是將匹配位置定位到字符串的開頭,直接來看一個例子

/*--------------------------第一種狀況--------------------*/

let pattern = /^javascript/
let str = "javascript is fun"

str.match(pattern)         //返回 ['javascript']

/*--------------------------第二種狀況--------------------*/

let pattern = /^javascript/
let str = "i love javascript"

str.match(pattern)         //返回 null

咱們匹配的模式是,要以javascript開頭的字符串。第一種狀況,字符串以 javascript開頭,因此能匹配到;第二種狀況,javascript不是在開頭的位置,而是在末尾的位置,不符合匹配模式,因此匹配失敗返回null。

在前面咱們有一個地方還用到了 ^ 這個符號,那就是 [^abc] ,因此必定要注意,當 ^ 放在方括號裏,表示的是取反,也就是說不匹配方括號裏的任何字符。

  • $ 符號

$ 這個符號是將匹配位置定位到字符串的末尾,直接來看一個例子

/*--------------------------第一種狀況--------------------*/

let pattern = /javascript$/
let str = "javascript is fun"

str.match(pattern)         //返回 null

/*--------------------------第二種狀況--------------------*/

let pattern = /javascript$/
let str = "i love javascript"

str.match(pattern)         //返回 ['javascript']

咱們的匹配模式是,字符串要以javascript結尾。第一種狀況,字符串結尾處字符是 fun ,不符合匹配模式,返回null;第二種狀況,結尾處字符爲javascript,符合匹配模式,因此匹配成功。

咱們能夠看一下若是 ^ 符號 和 $ 符號一塊兒使用是什麼狀況:

let pattern = /^javascript$/
let str = "javascript"

str.match(pattern)      //返回 ["javascript"]

當這兩個符號一塊兒使用時,匹配模式就變成了匹配整段字符串,而且字符串的內容就是 ^ 與 $ 之間的內容

  • \b

這個符號的做用是匹配一個單詞的邊界,咱們來看幾個例子來理解一下

/*-------------------------第一種狀況----------------------*/

let pattern = /\bjava/
let str = "I love javascript"

str.match(pattern)         // 返回 ['java'] 匹配成功

/*-------------------------第二種狀況----------------------*/

let pattern = /\bjava/
let str = "javascript is fun"

str.match(pattern)         // 返回 ['java'] 匹配成功

/*-------------------------第三種狀況----------------------*/

let pattern = /\bjava/
let str = "1javascript is fun"

str.match(pattern)         // 返回 null 匹配失敗

/*-------------------------第四種狀況----------------------*/

let pattern = /java\b/
let str = "I am learning java"

str.match(pattern)         // 返回 ['java'] 匹配成功

/*-------------------------第五種狀況----------------------*/

let pattern = /java\b/
let str = "I am learning javascript"

str.match(pattern)         // 返回 null 匹配失敗

/*-------------------------第六種狀況----------------------*/

let pattern = /\bjava\b/
let str = "I think java is fun"

str.match(pattern)         // 返回 ['java'] 匹配成功

看了上面幾個例子,你有沒有得出什麼規律?

其實 \b 的做用就是將匹配的點放到一個字符串前面(\b放前面)或後面(\b放後面)的 [^a-zA-Z0-9] 處,也能夠理解爲 \b 能夠替換那些特殊字符,但 \b 不會做爲匹配的內容。

  • \B

\B 則與 \b 相反了, \b 能夠替換那些特殊字符,那麼\B就是用來替換那些非特殊字符,也就是 [a-zA-Z0-9] 內的字符。

也來舉幾個簡單的例子吧

/*-------------------------第一種狀況----------------------*/

let pattern = /java\B/
let str = "I love javascript"

str.match(pattern)         // 返回 ['java'] 匹配成功

/*-------------------------第二種狀況----------------------*/

let pattern = /java\B/
let str = "I love java"

str.match(pattern)         // 返回 null 匹配失敗


/*-------------------------第三種狀況----------------------*/

let pattern = /\Bjava\B/
let str = "I love 1javascript"

str.match(pattern)         // 返回 ['java'] 匹配成功

/*-------------------------第四種狀況----------------------*/

let pattern = /\Bjava\B/
let str = "I love javascript"

str.match(pattern)         // 返回 null 匹配失敗
  • (?=p)

(?=p)表示接下來的字符要與p匹配,但p不會做爲內容返回

先來看一個例子

let pattern = /java(script)?(?=\:)/
let str = "java: my favorite language"

str.match(pattern)       //返回 ["java", undefined] 匹配成功

該例子的匹配模式:匹配一段字符串爲java 而後 script 能夠有一個也能夠沒有,後面必須跟一個 :,才能匹配成功,返回匹配內容,可是匹配內容中不包含 :

再來看一個相似的例子

let pattern = /java(script)?(?=\:)/
let str = "javascript is my favorite language"

str.match(pattern)       //返回 null 匹配失敗

該例子匹配失敗是由於字符串中的javascript後面沒有 :,沒有知足 (?=\:)的匹配要求

  • (?!p)

(?!p)與(?=p)相反,它表示接下來的字符不與p匹配

咱們也來看一個例子

let pattern = /java(?!script)/
let str = "javascript is my favorite language"

str.match(pattern)       //返回 null 匹配失敗

該例子的匹配模式是:匹配一段字符,只要java後面緊跟這的字符不是script即爲匹配成功,同時java後面跟的內容也不會做爲內容返回。但這個例子中的 str 裏, java後面緊跟着的就是script,因此匹配失敗。那麼成功的例子就是這樣的

let pattern = /java(?!script)/
let str = "javascr1111 is my favorite language"

str.match(pattern)       //返回 ["java"] 匹配成功

在該例子中, java 後面跟着的就不是script了,因此匹配成功了。java後面的字符不做爲內容返回,因此最後的匹配結果就是 java

修飾符

正則表達式的修飾符是用以說明高級匹配模式的規則,而且修飾符是放在// 雙斜槓外面的,例如這樣 /java/g,g就是修飾符

接下來給出一張表,列出了修飾符的種類和含義

字符 含義
i 執行不區分大小寫的匹配
g 執行全局匹配,即找到全部匹配的項並返回,而不是找到第一個以後就中止
m 多行匹配模式

咱們來逐個講解它們各自的用途:

  • 字符 i

咱們以前會用這樣的匹配模式去匹配 /[Jj]ava[Ss]cript/,這是由於咱們不知道字符串中寫的是 javascript 仍是 JavaScript。其實咱們能夠直接用一個修飾符 i 來避免大小寫的干擾,就想這樣 /javascript/i

let pattern = /javascript/i
let str = "JavaScript"

str.match(pattern)        // 返回 ['JavaScript'] 匹配成功

咱們能夠看到,匹配時忽略了大小寫的影響,仍然匹配成功了

  • 字符 g

咱們以前匹配字符串時,都是匹配到第一個就結束匹配返回內容,例如

let pattern = /java/
let str = "I love javascript and java"

str.match(pattern)      //返回 ["java"] 匹配到javascript的java就返回了

咱們能夠看到 str 字符串中,有兩個java,但只匹配到javascript就返回了,若是咱們要匹配到字符串中全部符合匹配模式的字符串,咱們就能夠用修飾符g,就像這樣 /java/g

let pattern = /java/g
let str = "I love javascript and java"

str.match(pattern)    //返回 ["java", "java"] 匹配到了全部的java
  • 字符 m

若是一個字符串中包含換行符,則該字符串就有多行。這時咱們可使用修飾符 m 進行多行模式的匹配。

let pattern = /java$/m
let str = "java\nis fun"

str.match(pattern)            //返回 ['java'] 匹配成功

在這個例子中,str內有一個換行符,這樣的話,第一行就是 java ,第二行就是 is fun 。咱們的匹配模式是查找每一行,只要這一行的結尾是java,就返回匹配到的內容。

其實在這個例子中,咱們看到,使用了修飾符 m 之後,錨字符 ^ 和 $ 再也不是以一整個字符串的開頭或結尾爲匹配點了,而是以每一行的開頭或結尾爲匹配點。

(3)用於模式匹配字符串的方法

咱們在前面的不少例子中用到了search()方法 、match()方法,他們都是匹配字符串的方法,其實還有不少種匹配的方法,他們的用法和做用各不相同,咱們來了解一下

用於模式匹配字符串的方法有如下幾種:

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

接下來咱們來詳細講解一下

search()

該方法須要傳入一個正則表達式做爲參數,並返回第一個與之匹配的字符串的起始位置,若沒匹配到,則返回-1

"javascript".search(/script/)      //返回 4

"javascript".search(/sccc/)        //返回-1

replace()

該方法是用於字符串的檢索與替換。須要傳入兩個參數,第一個參數爲正則表達式;第二個參數爲須要進行替換的字符串。匹配成功則會用第二個參數去替換匹配到的字符串,並返回替換後的總體字符串;若沒匹配成功,則返回原來的總體字符串。

"javascript".replace(/java/, 'python')  //返回 pythonscript

"javascript".replace(/abc/, 'python')   //返回 javascript

若使用了修飾符g,則會將全部匹配到的字符串都進行一個替換。

"javascript and java".replace(/java/, 'python')  //返回 pythonscript and java

"javascript".replace(/java/g, 'python')   //返回 pythonscript and python

match()

該方法須要傳入一個正則表達式做爲參數,返回一個由匹配結果組成的數組,若是正則表達式使用了修飾符g,則將全部匹配到的結果都放到數組中並返回。

"javascript and java".match(/java/)   //返回 ['java']

"javascript and java".match(/java/g)   //返回 ['java', 'java']

補充:當match()傳入一個非全局的正則表達式時,實際上返回的數組裏有兩個屬性:index和input,他們分別表示匹配到的字符串的起始位置和檢索的整個字符串。

let ret = "I love javascript and java".match(/java/)
ret.index        //返回 7
ret.input        //返回 I love javascript and java

split()

該方法是用於將字符串分割,並將分割開的部分做爲數組中的元素,最終返回一個數組。該方法須要傳入一個正則表達式做爲參數,去肯定須要根據什麼去分割這串字符串,若匹配成功,最終返回一個數組,數組中的元素就是每一個被分割的字符串;若匹配失敗,也會返回一個數組,數組中只有一個元素,那就是這個字符串總體。

'1,2,3,4,5,6'.split(/,/)   //返回 ['1', '2', '3', '4', '5', '6']

'1,2,3,4,5,6'.split(/\+/)  //返回 ['1,2,3,4,5,6']

4、new RegExp()

在第三部分講解正則表達式時,咱們都是用的直接量的形式建立的RegExp對象,其實使用直接量,在內部仍是會調用RegExp()構造函數去建立對象實例的,那咱們就來看看直接經過RexExp()構造函數是如何建立對象的吧。

RegExp()構造函數一共有兩個參數,第一個參數爲正則表達式的主體部分;第二個參數是可選的,爲修飾符。須要注意的是,咱們在寫主體部分的時候,有些地方要用一個反斜槓\進行轉義,咱們必須將一個反斜槓\ 替換成兩個反斜槓 \\。接下來咱們來看一下一個簡單的例子:

//建立一個RegExp對象,全局匹配字符串中連着的三個數字
let pattern = new RegExp("\\d{3}", "g")

這種建立RegExp對象的方法有一個好處,就是能夠動態的改變正則表達式的主體部分;而RegExp直接量就沒法作到動態變化。

RegExp對象的屬性

咱們建立的每一個RegExp對象(包括RegExp直接量)都包含有5個屬性:

  1. source:這是一個只讀屬性,包含正則表達式的文本,例如 /java/的source表示的就是 java
  2. global:這是一個只讀的布爾值,用以表示這個正則表達式是否使用了修飾符 g
  3. ignoreCase:這是一個只讀的布爾值,用以表示這個正則表達式是否使用了修飾符 i
  4. multiline:這是一個只讀的布爾值,用以表示這個正則表達式是否使用了修飾符 m
  5. lastIndex:這是一個可讀寫的整數值,若是匹配模式中有修飾符 g,則這個屬性會存儲下一次檢索的開始位置,這個屬性只有在調用exec()和test()兩個方法的時候會用到。

RegExp對象的方法

RegExp對象定義了兩個用於匹配的方法——exec()test(),這兩個方法與咱們以前講到的用於模式匹配字符串的方法不一樣的是,前者是定義在RegExp對象上的方法,而且傳入的參數是字符串;然後者是調用字符串的方法,傳入的參數是RegExp對象。

  • exec()

該方法就跟前面說到的不傳入修飾符g的matach()方法同樣,它對字符串執行一個正則表達式,若是匹配失敗,返回null;若是匹配成功,則返回一個數組,數組的第一個元素是正則表達式匹配到的字符串,剩下的元素則是子表達式匹配到的字符串,同時該數組也包含indexinput兩個屬性。

來看一個例子,體會一下exec()方法的做用

let pattern = new RegExp("java", "g")
let ret = pattern.exec("I love javascript and java")  //返回["java"]

ret.index     //返回 7
ret.input     //返回 I love javascript and java

exec()match() 方法不一樣的是,無論正則表達式是否使用修飾符g,exec()都只會將第一個匹配到的字符串以及子表達式匹配到的字符串放到數組裏返回;而match()方法在沒有使用修飾符g時,跟exec()同樣,若是使用了修飾符g,則將全部匹配到的字符串都放在數組裏一塊兒返回,而且不會返回圓括號裏匹配到的字符串,同時,該數組裏不包含indexinput兩個屬性。

那麼這裏引起一個疑問,既然無論是否使用修飾符g,exec()方法都只會返回第一個匹配到的字符串,那這個修飾符g有什麼用呢? 其實咱們在前面有說到,RegExp對象內有一個屬性叫作 lastIndex,該屬性默認爲0。當咱們調用exec()方法,而且使用了修飾符g進行匹配時,若匹配成功,lastIndex將變爲下一次檢索開始位置的索引值;若匹配失敗,lastIndex則重置爲0

let pattern = new RegExp("java", "g")
console.log(pattern.lastIndex)        //查看lastIndex默認爲0
let str = "I love javascript and java"

pattern.exec(str)               //進行第一次檢索匹配,返回["java"]
console.log(pattern.lastIndex)  //此時lastIndex爲 4

pattern.exec(str)               //進行第二次檢索匹配,返回["java"]
console.log(pattern.lastIndex)  //此時lastIndex爲 19

pattern.exec(str)               //進行第三次檢索匹配,返回null
console.log(pattern.lastIndex)  //此時lastIndex爲 0

從上面這個例子咱們能看看到,lastIndex默認爲0,表示從字符串的開頭開始檢索,當咱們進行第一次檢索時,匹配到了javascript中的java,返回了該字符串,這時lastIndex變爲第一次匹配到的字符串的起始位置索引 4;咱們進行第二次索引,是從索引 5 開始匹配的,日後檢索到字符串末尾的java,並返回該字符串,同時lastIndex變爲第二次匹配到的字符串起始位置索引 19;咱們進行第三次索引,是從索引 20 開始匹配的,日後匹配,已經沒法匹配到對應的字符串了,因此返回一個null,並將lastIndex重置爲0,表示下一次檢索又從字符串的開頭開始檢索。

  • test()

該方法與exec()相似,該方法也是傳入一個字符串做爲參數,對該字符串進行檢索,若是匹配到了相應的字符串,則返回true;若是沒匹配到,則返回false。

let pattern = new RegExp("java", "g")
let ret = pattern.test("I love javascript and java")  //返回 true

test() 與 exec() 相同的是,若是匹配時使用了修飾符g,test()也會根據對象內部屬性 lastIndex 進行檢索匹配,這裏就很少作說明了。

5、實戰應用

(1)判斷電話號碼格式

應用場景:判斷用戶輸入的電話號碼格式是否正確
電話號碼格式:1開頭,後面跟10位數字

let str = "12356456132"  //str爲用戶輸入的電話號碼
let re = /^1\d{10}$/     
if(re.test(str) !== true) {
	console.log('電話號碼格式不正確')
}
else {
	console.log('電話號碼格式正確')
}

(2)判斷郵箱格式

應用場景:判斷用戶輸入的郵箱格式是否正確
郵箱格式:第一部分@第二部分,第一部分由字母、數字 和 短橫線 - 組成,第二部分由(字母、數字、短橫線 - ).cn.com…… 組成

let str = "561325647@qq.com"    //用戶輸入的郵箱
let re = /^[\w-\.]+@(\w-?)+(\.\w{2,})+$/
if(re.test(str) !== true) {
	console.log('郵箱格式不正確')
}
else {
	console.log('郵箱格式正確')
}

(3)判斷暱稱格式

應用場景:判斷用戶輸入的暱稱是否符合規定格式
暱稱格式:暱稱由字母、數字、下劃線組成,必須由字母開頭,長度爲4-16位

let str = "Lpyexplore233"     //用戶輸入的暱稱
let re = /^[a-zA-Z][\w_]{3,15}$/
if(re.test(str) !== true) {
	console.log('暱稱格式不正確')
}
else {
	console.log('暱稱格式正確')
}

結束語

花了兩天的事件,本身從新完完整整地複習了一邊正則表達式,而且將知識點以博客的形式展示了出來,但願這篇文章能對你們有所幫助吧。喜歡的關注我,之後還會根據JavaScript不一樣部分的知識點進行整理並發表博客~

相關文章
相關標籤/搜索