學習JavaScript正則表達式之——字符匹配攻略 #1

正則表達式字符匹配策略

正則表達式是匹配模式,要麼匹配字符,要麼匹配位置(請務必記住這句話)javascript

1.1 兩種模糊匹配

若是正則只有精確匹配是沒有多少意義的,好比/hello/,也只能匹配字符串中的"hello" 這個子串。html

var regex = /hello/;
console.log(regex.test("hello")); 
// => true
複製代碼

正則表達式之因此強大,是由於其可以實現模糊匹配。java

而模糊匹配,有兩個方向上的模糊:橫向模糊縱向模糊git

1.1.1橫向模糊匹配

橫向模糊指的是,一個正則可匹配的字符串的長度是不固定的,能夠是多種狀況的,長度在宏觀角度可不就是橫向的嗎?正則表達式

其實現的方式是使用量詞、好比{m,n},表示連續出現 m 次,最多 n 次。express

好比正則 /ab{2,5}c/ 表示匹配這樣一個字符串,第一個字符是"a",接下來是 2到5個字符 "b",最後是字符 "c"。bash

其可視化的形式以下:ide

測試以下:測試

var regex = /ab{2,5}c/g;
var string = "abc abbc abbbc abbbbc abbbbbc abbbbbbc"
console.log(string.match(regex));
// => ["abbc","abbbc","abbbbc","abbbbbc"]
複製代碼

案例中的用的是 /ab{2,5}c/g 其中g 是正則的一個修飾符,表示全局匹配,即,在目標字符串中按照順序找到知足匹配模式的全部字串,強調是「全部」,而不是「第一個」。g 是單詞global 的首字母優化

1.1.2 縱向模糊匹配

縱向模糊匹配指的是,一個正則匹配的字符串,具體到某一位字符的時候,它能夠不是某個肯定的字符,能夠有多種可能。

其實現方式是使用字符組。好比[abc],表示該字符能夠是 "a","b","c"中的任何一個。

好比:/a[123]b/ 能夠匹配以下三種字符串 "a1b","a2b","a3b".

其可視化形式以下:

測試以下:

var regex = /a[123]b/g;
var string = "a0b a1b a2b a3b a4b";
console.log(string.match(regex));
// => ["a1b", "a2b", "a3b"]
複製代碼

以上就是介紹的兩種模糊匹配模式,只要掌握了橫向和縱向的模糊匹配,就可以解決大部分的正則匹配問題。

1.2字符組

須要強調的是,雖然字符組(字符類),但只是其中的一個字符。 例如[abc]表示匹配一個字符,他能夠是 「a」、「b「、」c「 之一。

1.2.1 範圍表示法

若是字符組裏面的字符特別多的話,怎麼辦?可使用範圍表示法。

好比 [123456abcdefGHIJKLM] 能夠寫成 [1-6a-fG-M]。用連字符 - 來省略和簡寫。

由於連字符有特殊的用途,那麼要匹配 "a"、"-"、"z" 這三者中任意一個字符,怎麼作呢?

不能寫成 [a-z],由於這種方式表示小寫字符中的任意一個字符。

能夠寫成以下方式:[-az] 或者 [az-] 或者 [a-z].

即要麼放在開頭,要麼放在結尾,要麼轉義,總之不會讓引擎認爲是範圍表示法就好了。

1.2.2 排除字符組

在縱向模糊匹配中,還有一種情形就是,某一個字符能夠是任何東西,但就是不能是"a"、"b"、"c".

這個時候就是排除字符組(反義字符組)的概念,例如[^abc].表示是一個除"a"、"b"、"c" 以外的任意一個字符,字符組的第一位放置 ^ (脫字符),表示求反的概念。

1.2.3 常見的簡寫形式

有了字符組的概念後,一些常見的符號咱們也就理解了。由於它們都是系統自帶的簡寫形式。

字符組 具體含義
\d 表示 [0-9]。表示是一位數字。 記憶方式:其英文是 digit(數字)。
\D 表示 [^0-9]。表示除數字外的任意字符。
\w 表示 [0-9a-zA-Z_]。表示數字、大小寫字母和下劃線。 記憶方式:w 是 word 的簡寫,也稱單詞字符。
\W 表示 [^0-9a-zA-Z_]。非單詞字符。
\s 表示 [ \t\v\n\r\f]。表示空白符,包括空格、水平製表符、垂直製表符、換行符、回車符、換頁 符。記憶方式:s 是 space 的首字母,空白符的單詞是 white space。
\S 表示 [^ \t\v\n\r\f]。 非空白符。
. 表示 [^\n\r\u2028\u2029]。通配符,表示幾乎任意字符。換行符、回車符、行分隔符和段分隔符 除外。記憶方式:想一想省略號 ... 中的每一個點,均可以理解成佔位符,表示任何相似的東西。

若是要匹配任意字符怎麼辦?可使用[\d\D]、[\w\W]、[\s\S] 和 [^] 中任何的一個。

以上各字符組對應的可視化形式是:

1.3量詞

1.3.1 簡寫形式

量詞也稱之爲重複,掌握{m,n}的準確含義以後,只須要記住一些簡寫形式。

字符組 具體含義
{m,} 表示至少出現m次
{m} 等價於 {m,m},表示出現 m 次。
? 等價於 {0,1},表示出現或者不出現。 記憶方式:問號的意思表示,有嗎?
+ 等價於 {1,},表示出現至少一次。 記憶方式:加號是追加的意思,得先有一個,而後才考慮追加。
* 等價於 {0,},表示出現任意次,有可能不出現。 記憶方式:看看天上的星星,可能一顆沒有,可能 零散有幾顆,可能數也數不過來

以上量詞 對應的可視的形式是:

1.3.2 貪婪匹配和惰性匹配

看下面的例子:

var regex = /\d{2,5}/g;
var string = "123 1234 12345 123456";
console.log(string.match(regex));
// => ["123", "1234", "12345", "12345"]
複製代碼

其中正則 /\d{2,5}/ 表示數字連續出現 2 到 5 次,會匹配 2 位 3 位 4 位 5 位連續的數字。

這種形式的【匹配模式實際上是貪婪的,它會盡量多的匹配 你給我 6 給我就要 5 個  你給我 3 個我就要 3 個。反正  在力所能及的範圍內,越多越好。

咱們知道有時候貪婪並非一件好事,而惰性匹配就是儘量少的  匹配。

var regex = /\d{2,5}?/g;
var string = "123 1234 12345 123456";
console.log(string.match(regex));
// => ["12", "12", "34", "12", "34", "12", "34", "56"]
複製代碼

其中 /\d{2,5}?/ 表示 雖然2到5次都行 當2個就夠的時候,就再也不往下嘗試了。

1.4 多選分支

一個模式能夠實現橫向和縱向的模糊匹配。而多選分支能夠支持多個子模式任選其一: 具體的形式以下:(p1|p2|p3) 其中p1,p2,p3 是子模式,用 |(管道符) 分割,表示其中任何之一。

例如要匹配字符串"good"和"nice" 可使用/good|nice/。

可視化形式以下:

測試以下:

var regex = /good|nice/g;
 var string = "good idea,nice try.";
 console.log( string match((regex)) );
 // => ["good","nice"] 
複製代碼

可是有個事實咱們應該注意,好比咱們用/good|goodbye/、去匹配 "goodbye"字符串時候 結果是 "good"

var regex = /good|goodbye/g;
var string = "goodbye";
console.log( string.match(regex) );
// => ['good']
複製代碼

若是將正則改爲/goodbye|good/,結果是:

var regex = /goodbye|good/g;
var string = "goodbye";
console.log( string.match(regex) );
// => ['goodbye']
複製代碼

也就是說,分支結構也是惰性的,即當前的模式匹配上了,後面的就不會再嘗試了。

1.5 案例分析

匹配字符,無非就是字符組,量詞和分支結構的組合使用罷了。 下面經過幾個例子演示一下使用方式:

1.5.1 匹配 16 進制的顏色值

要求匹配

##ffbbad
##Fc01DF
##FFF
##ffe
複製代碼

分析:

表示一個16進制,能夠用字符組[0-9a-fA-F]; 其中字符組能夠出現 3或者6次,須要使用量詞和分支結構。

使用分支結構的時候須要注意順序。

正則以下:

var regex = /#([0-9a-fA-F]{6}|[0-9a-fA-F]{3})/g;
var string = "#ffbbad #Fc01DF #FFF #ffE";
console.log( string.match(regex) );
// => ["#ffbbad", "#Fc01DF", "#FFF", "#ffE"]
複製代碼

可視化形式以下:

1.5.2 匹配時間

按照 24 小時爲例。

要求匹配:

23:59
 02:07
複製代碼

分析:

共4位數字,第一位數字能夠爲:[0-2].

當第一位爲"2"時,第二位能夠爲[0-3],其餘的狀況時,第二位爲[0-9].

第三位數字爲[0-5],第四位數字爲[0-9].

正則以下:

var regex = /^[01][0-9]|[2][0-3]:[0-5][0-9]$/;
  console.log(regex.test("23:59"));
  console.log(regex.test("02:07"));
  // => true
  // => true
複製代碼

注意:正則中使用到了 ^ 和 $ 分別表示字符串的開頭和結尾。

若是想要匹配7:9 說明時分前面的 0 能夠省略。

這個時候正則能夠變成:

var regex = /^(0?[0-9]|1[0-9]|[2][0-3]):(0?[0-9]|[1-5][0-9])$/;
  console.log(regex.test("23:59"));
  console.log(regex.test("02:07"));
  console.log(regex.test("7:9"));
  // => true
  // => true
  // => true
複製代碼

其可視化形式以下:

1.5.3 匹配日期:

好比:yyyy-mm-dd 格式爲例子。 要求匹配:

2017-06-10
複製代碼

分析: 年:四位數字便可 可使用[0-9]{4} 月:共計12個月,分爲兩種狀況"01"、"02"、…… "09" 和 "10"、"11"、"12" 可使用 (0[1-9]1[0-2]). 日:最大31天, 可使用(0[1-9]|[12][0-9]|3[01]]).

正則以下:

var regex = /^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$/; 
console.log( regex.test("2017-06-10") ); 
// => true
複製代碼

其可視化的形式以下:

1.5.4 window操做系統的文件路徑

要求匹配:

F:\study\javascript\regex\regular expression.pdf 
F:\study\javascript\regex\ 
F:\study\javascript 
F:\
複製代碼

分析: 總體的模式是:

盤符:\文件夾\文件夾\文件夾\
複製代碼

其中匹配:F:\ 須要使用 [a-zA-Z]:\\,其中 盤符不區分大小寫。注意\ 字符須要轉義.

文件名或者文件夾名 不能包含一些特殊字符、此時咱們須要使用經常使用的排除字符組:[^\\:*<>|"?\r\n/]來表示合法字符。

另外它們名字不能爲空的名 至少有一個字符,也就是須要使用量詞 + 所以匹配文件夾\的名稱可以使用 [^\\:*<>|"?\r\n/]+\\

另外 文件夾\ 能夠出現任意次數.也就是([^\\:*<>|"?\r\n/]+\\)* 其中括號表示其內部正則是一個總體。

路徑的最後一個部分還能夠是文件夾 沒有 \ 所以須要添加 ([^\\:*<>|"?\r\n/]+)?. 最後拼接成了一個正則:

var regex=/^[a-zA-Z]:\\([^\\:*<>|"?\r\n/]+\\)*([^\\:*<>|"?\r\n/]+)?$/
console.log(regex.test("F:\\study\\javascript\\regex\\regular expression.pdf")) 
console.log( regex.test("F:\\study\\javascript\\regex\\")) 
console.log( regex.test("F:\\study\\javascript"))
console.log( regex.test("F:\\"))
// => true 
// => true 
// => true 
// => true
複製代碼

其中在JavaScript中字符串須要表示字符 \ 時候也須要轉義。

可視化爲:

1.5.5 匹配 id

要求從:

<div id="container" class="main"></div>
複製代碼

提取出 id="container".

可能最開始想到的正則是:

var regex = /id=".*"/
 var string = '<div id="container" class="main"></div>'
 console.log(string.match(regex)[0]);
 // => id="container" class="main"
複製代碼

其可視化的形式是:

由於 . 是通配符 自己就是匹配雙引號,而量詞 * 又是貪婪的,當遇到 container 後面的雙引號時候,是不會 停下來,會繼續匹配,直到遇到最後一個雙引號爲止。

解決的辦法是使用惰性匹配:

var regex = /id=".*?"/
 var string = '<div id="container" class="main"></div>'
 console.log(string.match(regex)[0]);
 // => id="container"
複製代碼

固然這樣也會有一個問題就是效率比較低,由於匹配原理會涉及到回溯的概念,能夠優化以下:

var regex = /id="[^"]*"/
 var string = '<div id="container" class="main"></div>'
 console.log(string.match(regex)[0]);
 // => id="container"
複製代碼
相關文章
相關標籤/搜索