JavaScript的正規表示式

caoweiju發表於2017-10-21

正規表示式

正規表示式(Regular Expression)是一種文字模式,包括普通字元(例如,a 到 z 之間的字母)和特殊字元(稱為”元字元”)。
正規表示式使用單個字串來描述、匹配一系列匹配某個句法規則的字串。
通過使用正規表示式,可以:

  1. 測試字串內的模式。
    例如,可以測試輸入字串,以檢視字串內是否出現電話號碼模式或信用卡號碼模式。這稱為資料驗證。
  2. 替換文字。
    可以使用正規表示式來識別文件中的特定文字,完全刪除該文字或者用其他文字替換它。
  3. 基於模式匹配從字串中提取子字串。
    可以查詢文件內或輸入域內特定的文字。

目前,正規表示式已經在很多軟體中得到廣泛的應用,包括 *nix(Linux, Unix等)、HP 等作業系統,PHP、C#、Java 等開發環境,以及很多的應用軟體中,都可以看到正規表示式的影子。

特殊字元(稱為”元字元”)

正規表示式(regular expression)描述了一種字串匹配的模式(pattern),可以用來檢查一個串是否含有某種子串、將匹配的子串替換或者從某個串中取出符合某個條件的子串等。
構造正規表示式的方法和建立數學表示式的方法一樣。也就是用多種元字元與運算子可以將小的表示式結合在一起來建立更大的表示式。正規表示式的元件可以是單個的字元、字符集合、字元範圍、字元間的選擇或者所有這些元件的任意組合。
正規表示式是由普通字元(例如字元 a 到 z)以及特殊字元(稱為”元字元”)組成的文字模式。模式描述在搜尋文字時要匹配的一個或多個字串。正規表示式作為一個模板,將某個字元模式與所搜尋的字串進行匹配。

而往往正則的使用,那些元字元才是最為重要的部分,但是元字元真的不少,所以想要強記真的不容易,但是還是有一些使用場景較多的需要注意;

  1. 字元類別

    • 反斜槓
      將下一個字元標記為一個特殊字元、或一個原義字元、或一個 向後引用、或一個八進位制轉義符。例如,`n` 匹配字元 “n”。`n` 匹配一個換行符。序列 “ 匹配 “” 而 “(” 則匹配 “(“。
    • . 點號,
      匹配任意單個字元, 但是行結束符除外:n r u2028 或 u2029。
    • d
      匹配任一阿拉伯數字,等價於[0-9]
    • D
      匹配任意一個不是阿拉伯數字的字元。等價於1
    • w
      匹配任意來自基本拉丁字母表中的字母數字字元,還包括下劃線。等價於 [A-Za-z0-9_]。
    • W
      匹配任意不是基本拉丁字母表中單詞(字母數字下劃線)字元的字元。等價於 2
    • s
      匹配一個空白符,包括空格、製表符、換頁符、換行符和其他 Unicode 空格。 等價於 [ fnrtv​u00a0u1680​u180eu2000​u2001u2002​u2003u2004​ u2005u2006​u2007u2008​u2009u200a​u2028u2029​​u202fu205f​ u3000]。
    • []
      匹配一個退格符(backspace)(不要與 邊界匹配混淆)
    • S
      匹配一個非空白符
    • uhhhh
      匹配 Unicode 值為 hhhh (四個十六進位制數字)的字元。
  2. 字符集合

    • [xyz]
      一個字符集合,也叫字元組。匹配集合中的任意一個字元。你可以使用連字元`-`指定一個範圍。
    • [^xyz]
      一個反義或補充字符集,也叫反義字元組。也就是說,它匹配任意不在括號內的字元。你也可以通過使用連字元 `-` 指定一個範圍內的字元。
  3. 邊界

    • ^
      匹配輸入開始。如果多行(multiline)標誌被設為 true,該字元也會匹配一個斷行(line break)符後的開始處。
    • $
      匹配輸入結尾。如果多行(multiline)標誌被設為 true,該字元也會匹配一個斷行(line break)符的前的結尾處。

    • 匹配一個零寬單詞邊界(zero-width word boundary),如一個字母與一個空格之間。 (不要和 [b] 混淆)
    • B
      匹配一個零寬非單詞邊界(zero-width non-word boundary),如兩個字母之間或兩個空格之間。
  4. 分組(grouping)與反向引用(back references)

    • (x) 括號包括內容
      匹配 x 並且捕獲匹配項。 這被稱為捕獲括號(capturing parentheses)。例如,/(foo)/ 匹配且捕獲 “foo bar.” 中的 “foo”。被匹配的子字串可以在結果陣列的元素 [1], …, [n] 中找到,或在被定義的 RegExp 物件的屬性 $1, …, $9 中找到。捕獲組(Capturing groups)有效能懲罰。如果不需再次訪問被匹配的子字串,最好使用非捕獲括號(non-capturing parentheses),見下面的(?:x)。

    • 其中n 是一個正整數。一個反向引用(back reference),指向正規表示式中第 n 個括號(從左開始數)中匹配的子字串。例如,/apple(,)sorange1/ 匹配 “apple, orange, cherry, peach.” 中的 “apple,orange,”。一個更全面的例子在該表格下面。
    • (?:x)
      匹配 x 不會捕獲匹配項。這被稱為非捕獲括號(non-capturing parentheses)。匹配項不能夠從結果陣列的元素 [1], …, [n] 或已被定義的 RegExp 物件的屬性 $1, …, $9 再次訪問到。
  5. 數量詞(Quantifiers)

    • x*
      匹配前面的模式 x 0 或多次。
    • x+
      匹配前面的模式 x 1 或多次。等價於 {1,}。
    • x*? x+?
      像上面的 * 和 + 一樣匹配前面的模式 x,然而匹配是最小可能匹配。這是非貪婪匹配的寫法,主要是在量詞(* +)後面新增?來非貪婪匹配
    • x?
      匹配前面的模式 x 0 或 1 次。
    • x(?=y)
      只有當 x 後面緊跟著 y 時,才匹配 x【其中y是不算匹配結果的】。 例如,/Jack(?=Sprat)/ 只有在 `Jack` 後面緊跟著 `Sprat` 時,才會匹配它。/Jack(?=Sprat|Frost)/ 只有在 `Jack` 後面緊跟著 `Sprat` 或 `Frost` 時,才會匹配它。然而,`Sprat` 或 `Frost` 都不是匹配結果的一部分。
    • x(?!y)
      只有當 x 後面不是緊跟著 y 時,才匹配 x。例如,/d+(?!.)/ 只有當一個數字後面沒有緊跟著一個小數點時,才會匹配該數字。/d+(?!.)/.exec(“3.141”) 匹配 141 而不是 3.141。
    • x|y
      匹配 x 或 y
    • x{n}
    1. 是一個正整數。前面的模式 x 連續出現 n 次時匹配。
    • x{n,}
    1. 是一個正整數。前面的模式 x 連續出現至少 n 次時匹配。
    • x{n,m}
    1. 和 m 為正整數。前面的模式 x 連續出現至少 n 次,至多 m 次時匹配。
  6. 斷言(Assertions)

    • x(?=y)
      僅匹配被y跟隨的x。舉個例子,/Jack(?=Sprat)/,如果”Jack”後面跟著sprat,則匹配之。/Jack(?=Sprat|Frost)/ ,如果”Jack”後面跟著”Sprat”或者”Frost”,則匹配之。但是,”Sprat” 和”Frost” 都不會在匹配結果中出現。
    • x(?!y)
      僅匹配不被y跟隨的x。舉個例子,/d+(?!.)/ 只會匹配不被點(.)跟隨的數字。/d+(?!.)/.exec(`3.141`) 匹配”141″,而不是”3.141″

javascript的正規表示式物件

正規表示式是用於匹配字串中字元組合的模式。在 JavaScript中,正規表示式也是物件。這些模式被用於 RegExp 的 exec 和 test 方法, 以及 String 的 match、replace、search 和 split 方法。本章介紹 JavaScript正規表示式。

構建

var patt=new RegExp(pattern,modifiers);
或者更簡單的方式:
var patt=/pattern/modifiers;
//pattern(模式) 描述了表示式的模式
//modifiers(修飾符) 用於指定全域性匹配g、區分大小寫i的匹配和多行匹配m、Unicode序列u、粘性匹配y

有兩種方法來建立一個RegExp物件:一是字面量、二是建構函式。要指示字串,字面量的引數不使用引號,而建構函式的引數使用引號
當使用建構函式創造正則物件時,需要常規的字元轉義規則(在前面加反斜槓 ),下面兩個等價

var re = new RegExp("\w+");
var re = /w+/;

屬性

  1. RegExp.length 值為2
  2. RegExp.prototype.global
    是否開啟全域性匹配,也就是匹配目標字串中所有可能的匹配項,而不是隻進行第一次匹配。
  3. RegExp.prototype.ignoreCase
    在匹配字串時是否要忽略字元的大小寫。
  4. RegExp.prototype.lastIndex
    下次匹配開始的字串索引位置。
  5. RegExp.prototype.multiline
    是否開啟多行模式匹配(影響 ^ 和 $ 的行為)。
  6. RegExp.prototype.source
    正則物件的源模式文字。
  7. RegExp.prototype.sticky
    是否開啟粘滯匹配。

方法

1. RegExp.prototype.exec(str)

在目標字串中執行一次正則匹配操作。如果匹配成功,exec() 方法返回一個陣列,並更新正規表示式物件的屬性。返回的陣列將完全匹配成功的文字作為第一項,將正則括號裡匹配成功的作為陣列填充到後面。如果匹配失敗,exec() 方法返回 null。

當正規表示式使用 “g” 標誌時,可以多次執行 exec 方法來查詢同一個字串中的成功匹配。當你這樣做時,查詢將從正規表示式的 lastIndex 屬性指定的位置開始。(test() 也會更新 lastIndex 屬性)

var myRe = /ab*/g;
var str = `abbcdefabh`;
var myArray;
while ((myArray = myRe.exec(str)) !== null) {
  var msg = `Found ` + myArray[0] + `. `;
  msg += `Next match starts at ` + myRe.lastIndex;
  console.log(msg);
}

使用了g代表可以多次執行,執行exec返回的結果myArray[0]是匹配的全部字串,myArray[1], …[n ] 匹配的是括號中的分組捕獲,myArray是陣列,但是還有index屬性,匹配到的字元位於原始字串的基於0的索引值 ;以及input屬性,匹配的是原始字串。
myRe.exec()每執行完了一次之後,myRe也會發生變化,主要是屬性lastIndex的變化,下一次執行myRe.exec()都可以從這個更新的lastIndex處開始匹配;

注意:不要把正規表示式字面量(或者RegExp構造器)放在 while 條件表示式裡。由於每次迭代時 lastIndex的屬性都被重置,如果匹配,將會造成一個死迴圈。並且要確保使用了`g`標記來進行全域性的匹配,否則同樣會造成死迴圈。

如果你只是為了判斷是否匹配(true或 false),可以使用 RegExp.test() 方法,或者 String.search() 方法。

2. RegExp.prototype.test(str)

測試當前正則是否能匹配目標字串。test() 方法執行一個檢索,用來檢視正規表示式與指定的字串是否匹配。返回 true 或 false。

/^cwj(god)+/.test(`cwjgod`);  //true

JavaScript中的string和正則結合使用

String的match、replace、search和split方法都可以使用正規表示式。

match方法

str.match(regexp);

引數:
一個正規表示式物件。如果傳入一個非正規表示式物件,則會隱式地使用 new RegExp(obj) 將其轉換為一個 RegExp 。如果你未提供任何引數,直接使用 match() ,那麼你會得到一個包含空字串的 Array :[“”] 。
當引數是一個字串或一個數字,它會使用new RegExp(obj)來隱式轉換成一個 RegExp。如果它是一個有正號的正數,RegExp() 方法將忽略正號。
返回值:
一個包含了整個匹配結果以及任何括號捕獲的匹配結果的 Array ;如果沒有匹配項,則返回 null 。

如果正規表示式沒有 g 標誌,則 str.match() 會返回和 RegExp.exec() 相同的結果。而且返回的 Array 擁有一個額外的 input 屬性,該屬性包含被解析的原始字串。另外,還擁有一個 index 屬性,該屬性表示匹配結果在原字串中的索引(以0開始為整個匹配,1…n後面就是()括號裡面的子匹配)。

replace方法

這是一個強大的方法,

str.replace(regexp|substr, newSubStr|function)

引數1:以下二選一

  • regexp (pattern)
    一個RegExp 物件或者其字面量。該正則所匹配的內容會被第二個引數的返回值替換掉。
  • substr (pattern)
    一個要被 newSubStr 替換的字串。其被視為一整個字串,而不是一個正規表示式。僅僅是第一個匹配會被替換。

引數二:以下二選一

  • newSubStr (replacement)
    用於替換掉第一個引數在原字串中的匹配部分的字串。該字串中可以內插一些特殊的變數名。參考下面的使用字串作為引數。
  • function (replacement)
    一個用來建立新子字串的函式,該函式的返回值將替換掉第一個引數匹配到的結果。參考下面的指定一個函式作為引數。

在第一個引數是字串的時候,第二個字串可以是字串或者是函式:

  • 第二個引數是字串
    會有以下幾種特殊字元的存在,

    $$    代表插入一個 "$"。
    $&    代表插入匹配的子串。
    $`    代表插入當前匹配的子串左邊的內容。
    $`    代表插入當前匹配的子串右邊的內容。
  • 第二個引數是函式
    函式的返回值作為替換字串,引數match是匹配的子字串

在第一個引數是正規表示式的時候,第二個引數可以是字串或者函式

  • 第二個引數是字串

    $$    代表插入一個 "$"。
    $&    代表插入匹配的子串。
    $`    代表插入當前匹配的子串左邊的內容。
    $`    代表插入當前匹配的子串右邊的內容。
    $n    n 是個小於100的非負整數,那麼$n就代表第 n 個括號匹配的字串
  • 第二個引數是函式
    函式的返回值作為替換字串,引數如下:

    1.引數match是匹配的子字串
    2.引數【p1, p2,...】[$1, $2,...] 代表第n個括號匹配的字串
    3.offset 匹配到的子字串在原字串中的偏移量
    4.string  被匹配的原字串。

    這個引數順序是固定的,不能跳著寫,也就是說如果你需要offset,那麼必須把第一個引數在的全部匹配match以及所有的()子匹配都列出來在引數中,才能正確的對映到所有引數上

search方法

str.search(regexp)
  • 引數
    一個正規表示式(regular expression)物件。如果傳入一個非正規表示式物件,則會使用 new RegExp(obj) 隱式地將其轉換為正規表示式物件。
  • 返回值
    如果匹配成功,則 search() 返回正規表示式在字串中首次匹配項的索引。否則,返回 -1。

split方法

str.split([separator[, limit]])

split() 方法使用指定的分隔符字串將一個String物件分割成字串陣列,以將字串分隔為子字串,以確定每個拆分的位置。
兩個引數

  • separator
    指定表示每個拆分應發生的點的字串。separator 可以是一個字串或正規表示式。 如果純文字分隔符包含多個字元,則必須找到整個字串來表示分割點。如果在str中省略或不出現分隔符,則返回的陣列包含一個由整個字串組成的元素。如果分隔符為空字串,則將str原字串中每個字元的陣列形式返回。
  • limit
    一個整數,限定返回的分割片段數量。當提供此引數時,split 方法會在指定分隔符的每次出現時分割該字串,但在限制條目已放入陣列時停止。如果在達到指定限制之前達到字串的末尾,它可能仍然包含少於限制的條目。新陣列中不返回剩下的文字。

  1. 0-9
  2. A-Za-z0-9_

相關文章