天天看點

JavaScript的exec()和replace()方法

正規表達式通常被用來檢索、替換那些符合某個模式(規則)的文本。

正規表達式為了描述一個規則,往往需要用到大量的元字元,這些元字元要記下來并靈活運用,需要耗費很多的精力,而一般實際開發中卻很少用到正規表達式。此外為了保證複雜正規表達式是符合需求的,需要進行大量的字元串測試。是以這也是遇到需要用到複雜正規表達式實作的需求時,程式員表示非常難受(awsl)的原因。

盡管可能會用得比較少,但在某些場景下,使用正規表達式是最好的選擇,而且面試也可能會問到,是以還是要好好掌握一些比較基本的用法的。

因為不是本文的重點,而且知識點過多,這裡隻會 簡單描述一部分的元字元。如果你想系統地學習,可以閱讀文末提供的參考資料。

<col>

字元

含義

\

轉義字元

^

比對輸入開始

$

比對輸入結束

*

比對前一個表達式 0到多次。等價于{0,}

+

比對前一個表達式 1到多次。等價于{1,}

?

比對前一餓表達式 0或1次。等價于{0,1}

.

比對換行符外的任何單字元

(reg)

捕獲組,會捕獲括号裡面的比對項 reg。

(?:reg)

比對 'reg' 但不捕獲比對項。當我們需要将一段表達式作為一個整體,但又不想它被捕獲的時候,就可以這樣寫。比如 ​<code>​(?:ab)+​</code>​

x(?=y)

專業術語為 “先行斷言”。當 x 後面有 y 時,才比對 x。比對的子串将不會包含 y。

(?&lt;=x)y

“後行斷言”,和上一條同理。

x(?!y)

“正向否定查找”。比對一個 x 後面沒有 y 的 x

x|y

比對 x 或 y

{n}

比對前面一個字元(也可以是圓括号圍起來的一個子串) n 次,n必須為正整數。

{n, m}

比對前面的字元 n - m 次。m 可以省略,表示比對 n 次或更多。m 必須 大于或等于 n。如果 n 為 0,就是比對前面字元0次,相當于這個子串被忽略。

[xyz]

字元集合。比對方括号内的任意字元。我們也可以通過 ​<code>​-​</code>​ 來指定字元範圍,比如 [a-d] 等價于 [abcd],[1-4] 等價于 [1234],[\u4e00-\u9fa5] 則是比對一個漢字。​<code>​.​</code>​ 和 ​<code>​*​</code>​ 在方括号内沒有特殊含義,不需要進行轉義。

[\xyz]

比對沒有包含在方括号裡任何字元的字元。

[\b]

比對一個倒退符

\b

比對一個詞的邊界,比對位于邊界的單詞字元。。\b 并不能比對一個字元。如 ​<code>​\bm​</code>​ 可以比對 ​<code>​moon​</code>​,​<code>​oo\b​</code>​ 不能比對 moon。

比對非單詞邊界。如 \boo 比對 'noonday' 的 oo。

\d

比對一個數字,等價于 [0-9]

比對非數字。一般大寫表示對應小寫的特殊字元的反面。

\s

比對空白符

比對非空白符

\w

比對一個單字元(字母、數字或下劃線),等同于 [a-za-z0-9_],注意這個是比對不了漢字的。

與 \w 相反

\count

這裡的 count 代指一個正整數,等同于第n個子捕獲比對的子字元串(捕獲的數目以左括号計數)。這個其實挺有趣的。如 /a(b)(c)d\2\1/ 等同于 /a(b)(c)dcb/

|

分支條件

正規表達式預設使用 貪婪比對,即比對盡可能多的字元。但有時候我們希望可以比對盡可能少的字元,即 懶惰比對,我們可以在限定符(*、+、?、{n,m}這些指定重複數量的特殊字元)的後面添加 ​<code>​?​</code>​ 表示。如 ​<code>​a*?​</code>​ 表示比對 a 重複任意次,但盡可能少。

使用複雜的正規表達式會遇到的問題是,無法保證寫出的正規表達式是适用于所有對應的情況,這就需要我們做足夠多的測試。此外,正規表達式不是很好了解,需要做一些注釋才能直到它做了什麼事,一些語言允許在正規表達式使用注釋文法,但 js 并不支援。

如果是新手,建議使用 ​<code>​regexp.prototype.exec()​</code>​ 方法一個個進行測試來加深了解。

es6 中,正規表達式的功能得到了加強,并提供了更多的方法,本文不會讨論這些新方法。

g:全局搜尋。可以進行多次正則比對,而不是在發現第一個比對項時立即停止。

i:忽略大小寫

m:多行搜尋

y:粘連修飾符。除了第一次比對,剩餘的字元串必須從頭開始比對。es6 新增的标志符

u:unicode模式,可以處理四個位元組的 utf-16 編碼。es6 新增的标志符

方法

描述

exec

一個在字元串中執行查找比對的regexp方法,它傳回一個數組(未比對到則傳回null)。

test

一個在字元串中測試是否比對的regexp方法,它傳回true或false。

match

一個在字元串中執行查找比對的string方法,它傳回一個數組或者在未比對到時傳回null。

search

一個在字元串中測試比對的string方法,它傳回比對到的位置索引,或者在失敗時傳回-1。

replace

一個在字元串中執行查找比對的string方法,并且使用替換字元串替換掉比對到的子字元串。

split

一個使用正規表達式或者一個固定字元串分隔一個字元串,并将分隔後的子字元串存儲到數組中的string方法。

這些方法為 string 或 regexp 對象的方法。

正規表達式的 exec() 方法,是為 捕獲組 而設計的。

exec() 方法如果比對成功,會傳回一個 數組。這個數組除了數字索引外,還有一些其他的屬性。如果比對失敗,會傳回 null。

matches[n],n為索引值。matches[0] 是與整個模式比對的字元串。如果模式中有捕獲組(圓括号括起來的),matches[1] 到 matches[len-1] 為捕獲組比對到的字元串。如果捕獲組有嵌套的情況,順序為深度優先周遊的順序。

input:該屬性為被傳入的字元串,等于 text。

index:整個模式比對的字元串位于傳入字元串的位置,等同于 text.indexof(matches[0])

groups:具名組對象。es2018 引入了 具名組比對,支援如 ​<code>​/(?&lt;year&gt;\d{4})-(?&lt;month&gt;\d{2})-(?&lt;day&gt;\d{2})/​</code>​, 比對成功後, matches.groups.year 的值就是 matches[1]。

如果正規表達式帶上了 g 标志,每一次執行 exec() 方法,pattern(regexp 對象) 的 lastindex 都會變化,如果比對成功,為比對字元串的後一個索引位置。這個 lastindex 指定了輸入字元串的比對起始值。剛建立的 regexp 對象的 lastindex 為 0,你可以對其進行修改。如果沒有比對到,lastindex 會被設定為 0。

replace() 方法傳回一個由替換值(replacement)替換一些或所有比對的模式(pattern)後的新字元串。

第一個參數可以是字元串或正規表達式,如果提供的是字元串,隻會替換第一個子字元串。如果想替換所有子字元串,需要提供一個指定了 g 的正規表達式。

第二個參數可以是字元串或函數。

如果是字元串,可以使用一些特殊的 字元序列:

字元序列

替換文本

$(用于轉義)

$&amp;

比對整個模式的子串,與 regexp.lastmatch(非标準特性) 的值相等。

$`

目前比對的子串 左邊 的内容,與repexp.leftcontext(非标準屬性,請勿在生産環境中使用) 的值相同。

$'

目前比對的子串 右邊 的内容,與 regexp.rightcontentx(非标準屬性) 的值相同。

$n

這裡 n 取值為 1 - 99。位數隻有1個的話,可以加上前導零,如 ​<code>​$04​</code>​ 等同于 ​<code>​$4​</code>​。​<code>​$n​</code>​ 其實等價于 ​<code>​regexp.prototype.exec()​</code>​ 傳回的數組,但不同點在于, ​<code>​$0​</code>​ 是無效的,得使用 ​<code>​$&amp;​</code>​。n 超出了捕獲組的索引範圍,會替換為 "$n"(即失去特殊轉換的效果)。

下面的寫法,可以交換兩個單詞的位置。

如果第二個參數也可以是函數,這個函數接收多個參數:

match:比對的子串,等同于前面提到的 $&amp;

p1-p2:為捕獲組對應的比對字元串(如果設定了捕獲組)。

offset:模式比對項位于輸入字元串的位置

string:輸入的原始字元串。

函數的傳回值:傳回值即為替換的文本。

我們可以用它來實作 簡單的模版引擎(隻能替換文本):

如果你覺得此文對你有一丁點幫助,點個贊。或者可以加入我的開發交流群:1025263163互相學習,我們會有專業的技術答疑解惑

如果你覺得這篇文章對你有點用的話,麻煩請給我們的開源項目點點star: ​​https://gitee.com/zhongbangkeji/crmeb​​不勝感激 !