正則表達式:從Copy到手寫

1. RegExp對象

JavaScript有兩種方式實例化RegExp對象javascript

  • 字面量
  • 構造函數
字面量
const reg = /all/;
console.log(reg);   // /all/
'This is all I have.'.replace(reg, 'ALL');    // This is ALL I have.
構造函數
const reg = new RegExp('all');
console.log(reg);   // /all/
'This is all I have.'.replace(reg, 'ALL'); // This is ALL I have.

2. 元字符

  • 原義文本字符
  • 元字符
原義文本字符
表明它原本含義的字符。好比正則表達式爲 /abc//123/;它們分別匹配的是 abc123
元字符
在正則表達式中,有特殊含義的非數字字符。如: \b \d \w . + () 等。部分元字符的含義並不惟一,在不一樣的書寫方式,含義可能不一樣。

元字符表:http://tool.oschina.net/uploads/apidocs/jquery/regexp.htmlhtml

3. 工具推薦

不是全部正則表達式都像前面寫的那麼簡單,由於正則表達式語法有些複雜,咱們在寫的時候多多少少也會有些錯誤,或者閱讀別人寫的正則表達式的時候也難理解。java

若是把下面的正則表達式轉換成下圖,會有助於咱們理解正則表達式的含義。jquery

^http(|s):\/\/[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+\/$正則表達式

圖解

給你們推薦一個工具 https://regexper.comapi

4. 量詞

字符 含義
+ 出現一次或屢次(至少出現一次)
? 出現零次或一次(最多出現一次)
* 出現零次或屢次(任意次)
{n} 出現n次
{n, m} 出現n到m次
{n,} 至少出現n次
// \d表示匹配數字
// 匹配一個數字
'1234567890'.replace(/\d/, 'a'); // a234567890
// 匹配一個或多個數字(至少匹配一個)
'1234567890'.replace(/\d+/, 'a'); // a
'1234567890'.replace(/\d?/, 'a'); // a234567890
'1234567890'.replace(/\d*/, 'a'); // a
'1234567890'.replace(/\d{3}/, 'a'); // a4567890
'1234567890'.replace(/\d{2,4}/, 'a'); // a567890
'1234567890'.replace(/\d{3,}/, 'a'); // a
'12'.replace(/\d{3,}/, 'a'); // 12

使用工具 https://regexper.com/ 圖解數組

\d{2,6}函數

d{2,6}

5. 貪婪模式和非貪婪模式

從上面 4. 量詞 的例子中,'1234567890'.replace(/\d+/, 'a'); 輸出的是 a 而不是 a234567890'1234567890'.replace(/\d{2,4}/, 'a'); 輸出的是 a567890 而不是 a34567890工具

貪婪模式:正則表達式儘量多的匹配,一直到匹配失敗

非貪婪模式:正則表達式儘量少的匹配,一旦匹配成功就再也不匹配測試

由於默認狀況下,正則表達式都是使用貪婪模式作匹配的。若是想要讓正則表達式使用非貪婪模式匹配,在量詞後面加個 ? 便可。

'1234567890'.replace(/\d{2,4}/, 'a');  // a567890
'1234567890'.replace(/\d{2,4}?/, 'a'); // a34567890

'1234567890'.replace(/\d+/, 'a');      // a
'1234567890'.replace(/\d+?/, 'a');     // a234567890

6. 類

  • 正則表達式中,能夠使用 [] 來構建一個類,正則表達式中的類是指符合某些特性的對象

字符類

正則表達式 [abcd] 是把 abcd 歸爲一類,該表達式能夠匹配這類字符
'12345a6b7c8D9e'.replace(/[abcd]/g, '|');   // 12345|6|7|8D9e

範圍類

正則表達式提供了 [a-z] 來表示從 az 的任意字符(包含 az
'1a2b3c4q5z'.replace(/[a-z]/g, '|');   // 1|2|3|4|5|
'1a2b3c4T5Z'.replace(/[a-z]/g, '|');   // 1|2|3|4T5Z
'1a2b3c4T5Z'.replace(/[a-zA-Z]/g, '|');   // 1|2|3|4|5|
'1a2b3c4q5z'.replace(/[0-9]/g, '|');   // |a|b|c|q|z

[a-zA-Z0-9]

[a-zA-Z0-9]

預約義類

字符 等價於 含義
\d [0-9] 數字字符
\D [^0-9] 非數字字符
\w [a-zA-Z0-9_] 字母、數字、下劃線(單詞字符)
\W [^a-zA-Z0-9_] 非字母、數字、下劃線(非單詞字符)
\s [\t\n\x0B\f\r] 空白字符
\S [^\t\n\x0B\f\r] 非空白字符
. [^\n\r] 除了換行、回車以外的任意字符

7. 邊界

字符 含義
^ 以xxx開頭
$ 以xxx結尾
\b 單詞邊界
\B 非單詞邊界
'img/png/img-1.png'.replace(/img/g, 'image'); // image/png/image-1.png
'img/png/img-1.png'.replace(/^img/g, 'image'); // image/png/img-1.png

'img/png/img-1.png'.replace(/png/g, 'jpg'); // img/jpg/img-1.jpg
'img/png/img-1.png'.replace(/png$/g, 'jpg'); // img/png/img-1.jpg

'This is all I have.'.replace(/is/g, 'IS'); // ThIS IS all I have.
'This is all I have.'.replace(/\bis\b/g, 'IS'); // This IS all I have.
'This is all I have.'.replace(/\Bis\b/g, 'IS'); // ThIS is all I have.

9. 分組

做用

  • 與 | 使用
  • 與量詞使用
  • 反向引用

與 | 使用

/http(|s):\/\//

/http(|s):///

/http(|s):\/\//.test('https://');   // true
/http(|s):\/\//.test('http://');    // true
/a(b|c)d/.test('ad');               // false
/a(b|c)d/.test('abd');              // true
/a(b|c)d/.test('acd');              // true

與量詞使用

如何匹配 javascript 出現兩次 javascriptjavascript

/javascript{2}/.test('javascriptjavascript');    // false
/javascript{2}/.test('javascript');          // true
/(javascript){2}/.test('javascriptjavascript');  // true

反向引用

含有分組的正則表達式匹配成功時,將子表達式匹配到的內容,保存到內存中一個以數字編號的組裏,能夠簡單的認爲是對一個局部變量進行了賦值,這時就能夠經過反向引用方式,引用這個局部變量的值。

不少狀況下,咱們可能須要將某種格式的字符串轉換成另外一種格式的字符串。例如:將 05/28/2018 轉換成 2018-05-28;將Markdown語法的超連接 [Test](https://www.test.com/) 轉換成HTML的超連接 <a href="https://www.test.com/">Test</a>

'05/28/2018'.replace(/(\d{2})\/(\d{2})\/(\d{4})/, '$3-$1-$2');
// => 2018-05-28
'[Test](https://www.test.com/)'.replace(/\[(.+)\]\((http(|s):\/\/.+)\)/, '<a href="$2">$1</a>');
// => <a href="https://www.test.com/">Test</a>

忽略分組

有時候咱們在寫正則表達式的時候會屢次使用分組,但有一些分組是不須要反向引用的,好比正則表達式 /http(|s):\/\// 中的分組,咱們不須要進行反向引用,這時候咱們應該使用 (?:) 來忽略分組

不忽略分組:

/http(|s):\/\//

/http(|s):///

忽略分組:

/http(?:|s):\/\//

/http(|s):///

10. 前瞻後顧

  • 正則表達式是從頭部(左)向尾部(右)開始匹配的,文本的尾部方向稱爲「前」,文本的頭部方向稱爲「後」
  • 前瞻:正則表達式在匹配到規則的時候,向前檢查是否符合斷言
  • 後顧:正則表達式在匹配到規則的時候,向後檢查是否符合斷言
名稱 正則 含義
正向前瞻 exp(?=assert) 向前檢查符合斷言的
負向前瞻 exp(?!assert) 向前檢查不符合斷言的
正向後瞻 (?<=assert)exp 向後檢查符合斷言的
負向後瞻 (?<!assert)exp 向後檢查不符合斷言的
'ab1cde2fg'.replace(/[a-z](?=\d)/g, 'X'); // aX1cdX2fg
'ab1cde2fg'.replace(/[a-z](?!\d)/g, 'X'); // Xb1XXe2XX

'ab1cde2fg'.replace(/(?<=\d)[a-z]/g, 'X'); // ab1Xde2Xg
'ab1cde2fg'.replace(/(?<!\d)[a-z]/g, 'X'); // XX1cXX2fX

11. 修飾符

  • global: 是否全文搜索,默認 false
  • ignoreCase: 是否大小寫敏感,默認 false
  • multiline: 是否多行搜索,默認 false
  • lastIndex: 是當前表達式匹配內容的最後一個字符的下一個位置
  • source: 正則表達式的文本字符
'aaaaa'.replace(/a/, 'A');      // Aaaaa
'aaaaa'.replace(/a/g, 'A');     // AAAAA

'aAQq'.replace(/[a-z]/g, 'X'); // XAQX
'aAQq'.replace(/[a-z]/gi, 'X'); // XXXX

/[a-z]/.test('AA');    // false
/[a-z]/i.test('AA');    // true

`img/png/img-1.png
img/png/img-1.png
img/png/img-1.png`.replace(/^img/g, 'image');
// => image/png/img-1.png
//    img/png/img-1.png
//    img/png/img-1.png
`img/png/img-1.png
img/png/img-1.png
img/png/img-1.png`.replace(/^img/gm, 'image');
// => image/png/img-1.png
//    image/png/img-1.png
//    image/png/img-1.png
const reg = /\d/gim;
console.log(reg.source);    // \d

12. RegExp對象中 test() 和 exec()

test()

用於測試參數字符串中是否存在匹配正則表達式模式的字符串;若是存在則返回true,不然返回false
const reg = /\w/;
reg.test('|'); // false
reg.test('a'); // true
reg.test('a'); // true

當使用 g 全文搜索時,test 函數會出現以下問題:

test

上述問題實際上是正則表達式對象的 lastIndex 屬性在做怪

test

若是正則表達式使用了全文搜索 g ,又想避免上述問題,應在執行 test 函數前先將 lastIndex0

const reg = /\w/g;
reg.test('ab'); // true
reg.lastIndex = 0;
reg.test('ab'); // true
reg.lastIndex = 0;
reg.test('ab'); // true

exec()

使用正則表達式模式對字符串執行搜索,並將匹配到的結果以數組形式返回,若是沒有匹配,返回null

exec

結果數組屬性

  • index:匹配字符的第一個字符的位置
  • input:被匹配的字符串

返回的數組

  • 第一個元素是與正則表達式匹配的內容
  • 第二個元素是與第一個子表達式相匹配的內容
  • 第三個元素是與第二個子表達式相匹配的內容(以此類推)

現有以下字符串數組,咱們使用 exec 從每一個元素中提取圖片的路徑

const arr = [
    '[測試1](https://www.test1.com/img/img-1.png)',
    '[測試1](http://www.test1.com/img/img-1.jpg)',
    '[測試2](https://static.test2.com/image/haha/img-1.png)'
]

正則表達式:

const reg = /\[.+\]\(http(|s):\/\/[a-zA-Z0-g_-]+(\.[a-zA-Z0-9_-]+)+\/((.+\/)+.+\.(png|jpg))\)/;

exec

const res = reg.exec(arr[2]);

exec

上述正則表達式使用了較多的分組,咱們在閱讀圖形的時候可能形成干擾,忽略沒必要要的分組。

const reg2 = /\[.+\]\(http(?:|s):\/\/[a-zA-Z0-g_-]+(?:\.[a-zA-Z0-9_-]+)+\/((?:.+\/)+.+\.(?:png|jpg))\)/;

exec

reg2.exec(arr[2]);

exec

相關文章
相關標籤/搜索