JavaScript 正則表達式全面總結

本文適合有 JavaScript 基礎 && 面向搜索引擎書寫正則的人羣。es6

正則表達式是用於匹配字符串中字符組合的模式。正則表達式的模式規則是由一個字符序列組成的。包括全部字母和數字在內,大多數的字符都是直接按照直接量描述待匹配的字符。除此以外,正則表達式還有其餘特殊語義的字符,這些字符不按照特殊含義進行匹配。正則表達式

建立正則表達式

JavaScript 中的正則表達式用 RegExp 對象表示,有兩種建立方式。數組

1. 直接量語法建立

正則表達式直接量定義爲包含在一對斜槓(/)之間的字符。函數

2. 構造函建立

能夠經過 RegExp() 構造函數能夠實現動態建立正則表達式。RegExp 的第二個參數是可選的。搜索引擎

new RegExp(pattern [, flags])
RegExp(pattern [, flags])

其中 pattern 能夠是字符串或者正則字面量。當 pattern 是字符串時,須要常規的字符轉義規則,必須將 \ 替換成 \\,好比 /\w+/ 等價於 new RegExp("\\w+")編碼

直接量字符

正則表達式中全部字母和數字都是按照字面含義進行匹配的,其餘非字母的字符須要經過反斜槓(\)做爲前綴進行轉移,如 \n 匹配換行符。這些字符爲直接量字符(literal characters)。這些字符都是精確匹配,每個字符都只能匹配一個字符。spa

在正則表達式中,有一些標點符號具備特殊含義,他們是:^ $ . * + ? = ! : | \ / ( ) [ ] { } 若是須要在正則表達式中與這些直接量進行匹配,必須使用前綴 \prototype

若是不記得哪些標點須要反斜槓轉義,能夠在每一個標點符號前都加上反斜槓。code

字符類

若是不想匹配某一個特定的字符而是想匹配某一類字符,則須要使用字符類。regexp

經過將直接量字符放入方括號內,能夠組成字符類(character class)。一個字符類能夠匹配它所包含任意 一個 字符。如 [abc] 能夠匹配 a,b,c 中任意一個字符。

使用 ^ 做爲方括號中第一個字符來定義否認字符集,它匹配全部不包含在方框括號內的字符。[^] 能夠匹配任意字符。

字符類可使用連字符來表示字符範圍。好比匹配小寫字母[a-z],匹配任何字母和數字能夠用[a-zA-Z0-9]

一些經常使用的字符類,在 JavaScript 中有特殊的轉義字符來表達它們。

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

方括號內也可出現轉義字符,如 [\d\s] 表示匹配任意空白符或數字。

重複

當一個模式須要被屢次匹配的時候,正則表達式提供了表示重複的正則語法。

字符 含義
{n,m} 匹配前一項至少 n 次,但不能超過 m 次
{n,} 匹配前一項至少 n 次
{n} 匹配前一項 n 次
? 匹配前一項 0 次或 1 次,等價於 {0,1}
+ 匹配前一項 1 次或屢次,等價於 {1,}
* 匹配前一項 0 次或屢次,等價於 {0,}

貪婪和非貪婪的重複

上面全部的重複都是「貪婪的」匹配,也就是匹配儘量多的字符。如 /a+/ 匹配 'aaaa' 時,它會匹配 'aaaa'

若是想要儘量少的匹配,只須要在重複的標記後加一個問號(?)便可。如 /a+?/ 匹配 'aaaa' 時,它會匹配 'a'

注意:正則表達式的模式匹配總會尋找字符串中第一個可能匹配的位置,這意味這 /a+?b/ 匹配 'aaab' 時,匹配到的是 'aaab' 而不是 'ab'

選擇、分組和引用

選擇

字符 | 用於分隔供選擇的模式,匹配時會嘗試從左到右匹配每個分組,直到發現匹配項。如 /ab|bc|cd/ 能夠匹配字符串'ab''bc''cd'

分組

圓括號能夠把單獨的項組合成子表達式,以即可以像一個獨立的單元用 |*+ 或者 ? 對單元內的項進行處理。

引用

帶圓括號的表達式的另外一個用途是容許在同一個正則表達式的後面引用前面的子表達式。經過\後面加數字實現。\n 表示第 n 個帶圓括號的子表達式。表示引用前一個表達式所匹配的文本。由於子表達式能夠嵌套,因此根據子表達式左括號的位置進行計數。

例,能匹配 1999-01-01 或 1999/01/01 的正則:/\d{4}([-\/])\d{2}\1\d{2}/

具名引用

使用 (?<name>...) 的語法來爲分組命名,並經過 \k<name> 在後面的正則表達式中引用。如上面的正則能夠改寫爲:/\d{4}(?<separator>[-\/])\d{2}\k<separator>\d{2}/

忽略引用

若是隻想用圓括號來表示子表達式,而不但願生成引用,可使用 (?:) 來進行分組。例,/(?:a)(?:b)(c)/\1 將表示 (c) 所匹配的文本。

指定匹配位置(錨元素)

有一些正則表達式的元素不用來匹配實際的字符,而是匹配指定的位置。咱們稱這些元素爲正則表達式的錨。

正則表達式中的錨字符包括:

  • ^ 用來匹配字符串的開始,多行檢索時匹配一行的開頭。
  • $ 用來匹配字符串的結束,多行檢索時匹配一行的結尾。
  • \b 用來匹配單詞的邊界,就是 \w\W 之間的位置,或者 \w 和字符串的開頭或結尾之間的位置。
  • \B 匹配非單詞邊界的位置。

例: /\bJava\b/ 能夠匹配 Java 卻不匹配 JavaScript

任意正則表達式均可以做爲錨點條件。

先行斷言

(?=pattern) 它表示一個位置,該位置以後的字符能匹配 pattern 。如 /\d+(?=%)/ 匹配字符串 '100%' 中的 '100' 可是不匹配 '100。'

負向先行斷言

(?!pattern) 它表示一個位置,該位置以後的字符能不匹配 pattern

後行斷言

(?<=pattern) 它表示一個位置,該位置以前的字符能匹配 pattern 。例,/(?<=\$)\d+/ 匹配 '$100' 可是不匹配 '¥100'

負向後行斷言

(?<!pattern) 它表示一個位置,該位置以前的字符能不匹配 pattern

修飾符

在正則表達式的第二條斜線以後,能夠指定一個或多個修飾符,/pattern/g

經常使用修飾符:

  • i 執行不區分大小寫的匹配。
  • g 全局匹配。
  • m 多行匹配模式。
  • y 「粘連」(sticky)修飾符。y修飾符的做用與g修飾符相似,也是全局匹配,後一次匹配都從上一次匹配成功的下一個位置開始。不一樣之處在於,g修飾符只要剩餘位置中存在匹配就可,而y修飾符確保匹配必須從剩餘的第一個位置開始,這也就是「粘連」的涵義。
  • s 表示點(.)能夠表示任意字符,不設置的話,四個字節的 UTF-16 字符和行終止符不能用 . 表示。
  • u 開啓 「Unicode 模式」,用來正確處理大於 \uFFFF 的 Unicode 字符。也就是說,會正確處理四個字節的 UTF-16 編碼。

經過 RegExp.prototype.flags 能夠得到正則修飾符的字符串。/pattern/ig.flags 返回 "gi"

字符串的正則方法

String.prototype.search(regexp|substr)

返回第一個和參數匹配的子串的起始位置。沒有匹配子串返回 -1

若是參數不是正則表達式,將會經過 RegExp 構造函數轉換成正則表達式。它會忽略正則的修飾符 g

String.prototype.replace(regexp|substr, newSubStr|function)

第一個參數同search,查找指定子串。若是第二個表達式是字符串,將把第一個參數匹配的子串替換爲 newSubStr。若是在替換字符串中出現了 $ 加數字,replace 將用與指定的子表達式相匹配的文原本替換這些字符。

例,單書名號包裹文本改成書名號。'<JavaScript>和<正則表達式>'.replace(/<([^_]*?)>/g, '《$1》') 會獲得 "《JavaScript》和《正則表達式》"

使用字符串做爲參數時替換字符串能夠插入下面的特殊變量名:

  • $$ 插入一個 "$"
  • $& 插入匹配的子串。
  • `$`` 插入當前匹配的子串左邊的內容。
  • $' 插入當前匹配的子串右邊的內容。
  • $n 假如第一個參數是 RegExp對象,而且 n 是個小於100的非負整數,那麼插入第 n 個括號匹配的字符串。提示:索引是從1開始

使用函數做爲第二個參數

function replacer(match, p1, p2, p3, offset, string) { }
// match        匹配的子串。
// p1,p2, ...   假如replace()方法的第一個參數是一個RegExp 對象,則表明第n個括號匹配的字符串。
// offset       匹配到的子字符串在原字符串中的偏移量。子串首字母下標。
// string       被匹配的原字符串。

例,下劃線命名轉駝峯命名。'a_simple_name'.replace(/_([a-z])/g, (m, p1) => p1.toUpperCase()) 將獲得 "aSimpleName"

String.prototype.match(regexp)

參數 regexp 爲一個正則表達式對象。若是傳入一個非正則表達式對象,則會隱式地使用 new RegExp(obj) 將其轉換爲一個 RegExp

若是 regexp 沒有設置修飾符 g,則僅返回第一個完整匹配及其相關的捕獲組(Array),返回數組第一個字符是匹配字符串,餘下的元素是正則表達式中圓括號括起來的子表達式。在這種狀況下,返回的項目將具備以下所述的其餘屬性(groups: 一個捕獲組數組 或 undefined(若是沒有定義命名捕獲組)。index: 匹配的結果的開始位置。input: 搜索的字符串。),或者未匹配時返回 null

若是使用 g 標誌,則將返回與完整正則表達式匹配的全部結果,但不會返回捕獲組,或者未匹配時返回 null

'196.168.0.1'.match(/(\d+)(?=.|$)/) // (?=.|$) 先行匹配 匹配 . 或者字符串結尾
// (2) ["196", "196", index: 0, input: "196.168.0.1", groups: undefined]
'196.168.0.1'.match(/(?<num>\d+)(?=.|$)/) // (?<name>) 具名引用 見上文
// (2) ["196", "196", index: 0, input: "196.168.0.1", groups: {num: "196"}]
'196.168.0.1'.match(/\d+(?=.|$)/g)
// (4) ["196", "168", "0", "1"]

String.prototype.split([separator[, limit]])

separator 指定表示每一個拆分應發生的點的字符串,能夠是一個字符串或正則表達式。若是空字符串("")被用做分隔符,則字符串會在每一個字符之間分割。

limit 一個整數,限定返回的分割片斷數量。

例,'張三;李四,王五|趙六'.split(/[;\|,]/) // (4) ["張三", "李四", "王五", "趙六"]

RegExp 的屬性

  • flags 會返回正則表達式的修飾符。
  • 表示對應修飾符是否存在的只讀布爾值,global(表示是否帶有修飾符 g),ignoreCasei),multilinem),stickyy),dotAlls),unicodeu
  • source 只讀字符串,包含正則表達式的文本。
  • lastIndex 可讀/寫整數。若是帶有 g 修飾符,這個屬性存儲在整個字符串中下一次檢索的開始位置。這個屬性會被 exec()test() 方法用到。

RegExp 的方法

exec()

若是沒有找到任何屬性,將返回 null,若是找到匹配返回一個數組,該數組第一個元素是相匹配的字符串,餘下的元素是與圓括號內的子表達式相匹配的子串。

當調用 exec() 的正則表達式具備修飾符 g 時,它將把當前正則表達式對象的 lastIndex 屬性設置爲緊挨着匹配子串的字符位置。

注意即便兩次匹配的不是同一個字符串,lastIndex 仍是會連續生效的。

let reg = /\d+/g;
reg.exec('25*10=250'); // ["25", index: 0, input: "25*10=250", groups: undefined]
reg.lastIndex; // 2
reg.exec('666'); // ["6", index: 2, input: "666", groups: undefined]
reg.lastIndex; // 3

test()

調用 test()exec() 等價,當 exec() 返回結果不是 nulltest() 返回 true,不然返回 false

String 的方法不會用到 lastIndex 屬性。

參考資料

相關文章
相關標籤/搜索