【正則表達式】JavaScript的exec()和search()方法

本文簡單介紹了正則表達式的元字符,和 JavaScript 提供的兩個和正則表達式有關的方法:RegExp.prototype.exec()String.prototype.replace()html

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

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

儘管可能會用得比較少,但在某些場景下,使用正則表達式是最好的選擇,並且面試也可能會問到,因此仍是要好好掌握一些比較基本的用法的。es6

正則表達式的元字符

由於不是本文的重點,並且知識點過多,這裏只會 簡單描述一部分的元字符。若是你想系統地學習,能夠閱讀文末提供的參考資料。面試

字符 含義
\ 轉義字符
^ 匹配輸入開始
$ 匹配輸入結束
* 匹配前一個表達式 0到屢次。等價於{0,}
+ 匹配前一個表達式 1到屢次。等價於{1,}
? 匹配前一餓表達式 0或1次。等價於{0,1}
. 匹配換行符外的任何單字符
(reg) 捕獲組,會捕獲括號裏面的匹配項 reg。
(?:reg) 匹配 'reg' 但不捕獲匹配項。當咱們須要將一段表達式做爲一個總體,但又不想它被捕獲的時候,就能夠這樣寫。好比 (?:ab)+
x(?=y) 專業術語爲 「先行斷言」。當 x 後面有 y 時,才匹配 x。匹配的子串將不會包含 y。
(?<=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] 字符集合。匹配方括號內的任意字符。咱們也能夠經過 - 來指定字符範圍,好比 [a-d] 等價於 [abcd],[1-4] 等價於 [1234],[\u4e00-\u9fa5] 則是匹配一個漢字。.* 在方括號內沒有特殊含義,不須要進行轉義。
[\xyz] 匹配沒有包含在方括號裏任何字符的字符。
[\b] 匹配一個退格符
\b 匹配一個詞的邊界,匹配位於邊界的單詞字符。。\b 並不能匹配一個字符。如 \bm 能夠匹配 moonoo\b 不能匹配 moon。
\B 匹配非單詞邊界。如 \Boo 匹配 'noonday' 的 oo。
\d 匹配一個數字,等價於 [0-9]
\D 匹配非數字。通常大寫表示對應小寫的特殊字符的反面。
\s 匹配空白符
\S 匹配非空白符
\w 匹配一個單字符(字母、數字或下劃線),等同於 [A-Za-z0-9_],注意這個是匹配不了漢字的。
\W 與 \w 相反
\count 這裏的 count 代指一個正整數,等同於第n個子捕獲匹配的子字符串(捕獲的數目以左括號計數)。這個其實挺有趣的。如 /a(b)(c)d\2\1/ 等同於 /a(b)(c)dcb/
| 分支條件

正則表達式默認使用 貪婪匹配,即匹配儘量多的字符。但有時候咱們但願能夠匹配儘量少的字符,即 懶惰匹配,咱們能夠在限定符(*、+、?、{n,m}這些指定重複數量的特殊字符)的後面添加 ? 表示。如 a*? 表示匹配 a 重複任意次,但儘量少。正則表達式

使用複雜的正則表達式會遇到的問題是,沒法保證寫出的正則表達式是適用於全部對應的狀況,這就須要咱們作足夠多的測試。此外,正則表達式不是很好理解,須要作一些註釋才能直到它作了什麼事,一些語言容許在正則表達式使用註釋語法,但 js 並不支持。數組

若是是新手,建議使用 RegExp.prototype.exec() 方法一個個進行測試來加深理解。bash

ES6 中,正則表達式的功能獲得了增強,並提供了更多的方法,本文不會討論這些新方法。ide

標誌符

  • g:全局搜索。能夠進行屢次正則匹配,而不是在發現第一個匹配項時當即中止。
  • i:忽略大小寫
  • m:多行搜索
  • y:粘連修飾符。除了第一次匹配,剩餘的字符串必須從頭開始匹配。ES6 新增的標誌符
  • u:Unicode模式,能夠處理四個字節的 UTF-16 編碼。ES6 新增的標誌符

使用到正則表達式的 javaScript 原生方法

方法 描述
exec 一個在字符串中執行查找匹配的RegExp方法,它返回一個數組(未匹配到則返回null)。
test 一個在字符串中測試是否匹配的RegExp方法,它返回true或false。
match 一個在字符串中執行查找匹配的String方法,它返回一個數組或者在未匹配到時返回null。
search 一個在字符串中測試匹配的String方法,它返回匹配到的位置索引,或者在失敗時返回-1。
replace 一個在字符串中執行查找匹配的String方法,而且使用替換字符串替換掉匹配到的子字符串。
split 一個使用正則表達式或者一個固定字符串分隔一個字符串,並將分隔後的子字符串存儲到數組中的String方法。

這些方法爲 String 或 RegExp 對象的方法。函數

RegExp.prototype.exec()

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

const pattern = /a(bc(1))(de)/g
const text = `-abc1de-`;
const matches = pattern.exec(text);
複製代碼

exec() 方法若是匹配成功,會返回一個 數組。這個數組除了數字索引外,還有一些其餘的屬性。若是匹配失敗,會返回 null。

  • matches[n],n爲索引值。matches[0] 是與整個模式匹配的字符串。若是模式中有捕獲組(圓括號括起來的),matches[1] 到 matches[len-1] 爲捕獲組匹配到的字符串。若是捕獲組有嵌套的狀況,順序爲深度優先遍歷的順序。
  • input:該屬性爲被傳入的字符串,等於 text。
  • index:整個模式匹配的字符串位於傳入字符串的位置,等同於 text.indexOf(matches[0])
  • groups:具名組對象。ES2018 引入了 具名組匹配,支持如 /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/, 匹配成功後, matches.groups.year 的值就是 matches[1]。

若是正則表達式帶上了 g 標誌,每一次執行 exec() 方法,pattern(RegExp 對象) 的 lastIndex 都會變化,若是匹配成功,爲匹配字符串的後一個索引位置。這個 lastIndex 指定了輸入字符串的匹配起始值。剛建立的 RegExp 對象的 lastIndex 爲 0,你能夠對其進行修改。若是沒有匹配到,lastIndex 會被設置爲 0。

String.prototype.replace

replace() 方法返回一個由替換值(replacement)替換一些或全部匹配的模式(pattern)後的新字符串。

str.replace(regexp|substr, newSubStr|function)
複製代碼

第一個參數能夠是字符串或正則表達式,若是提供的是字符串,只會替換第一個子字符串。若是想替換全部子字符串,須要提供一個指定了 g 的正則表達式。

第二個參數能夠是字符串或函數。

若是是字符串,可使用一些特殊的 字符序列

字符序列 替換文本
$$ $(用於轉義)
$& 匹配整個模式的子串,與 RegExp.lastMatch(非標準特性) 的值相等。
$` 當前匹配的子串 左邊 的內容,與RepExp.leftContext(非標準屬性,請勿在生產環境中使用) 的值相同。
$' 當前匹配的子串 右邊 的內容,與 RegExp.rightContentx(非標準屬性) 的值相同。
$n 這裏 n 取值爲 1 - 99。位數只有1個的話,能夠加上前導零,如 $04 等同於 $4$n 其實等價於 RegExp.prototype.exec() 返回的數組,但不一樣點在於, $0 是無效的,得使用 $&。n 超出了捕獲組的索引範圍,會替換爲 "$n"(即失去特殊轉換的效果)。

下面的寫法,能夠交換兩個單詞的位置。

'bar foo'.replace( /(...) (...)/, '$2 $1' )
// -> 'foo bar'
複製代碼

若是第二個參數也能夠是函數,這個函數接收多個參數:

function (match[,p1, p2, ..., pn], offset, string)
複製代碼
  • match:匹配的子串,等同於前面提到的 $&
  • p1-p2:爲捕獲組對應的匹配字符串(若是設置了捕獲組)。
  • offset:模式匹配項位於輸入字符串的位置
  • string:輸入的原始字符串。
  • 函數的返回值:返回值即爲替換的文本。

咱們能夠用它來實現 簡單的模版引擎(只能替換文本):

const pattern = /\{\{\s*(.*?)\s*\}\}/g,
const data = {
    name: '李田所',
    age: 24,
    job: '學生'
}
const text = `我是{{name}},今年{{ age }}歲,是個{{ job}}。`;


const renderResult = text.replace(pattern, function(match, p1, offset, string) {
    return data[p1]
})
console.log(renderResult)
// -> 我是李田所,今年24歲,是個學生。
複製代碼

參考

  1. 正則表達式30分鐘入門教程
  2. 正則表達式 - MDN
  3. Array - MDN
  4. ES6入門
  5. RegExp.prototype.exec() - MDN
  6. String.prototype.replace() - MDN
  7. 廢棄和過期的JavaScript特性
  8. 淺談模板引擎
相關文章
相關標籤/搜索