一次性搞懂JavaScript正則表達式之語法

本文是『horseshoe·Regex專題』系列文章之一,後續會有更多專題推出javascript

GitHub地址:github.com/veedrin/hor…前端

博客地址(文章排版真的很漂亮):matiji.cnjava

若是以爲對你有幫助,歡迎來GitHub點Star或者來個人博客親口告訴我git


名餘曰正則兮,字餘曰靈均。github

Regular Expressions翻譯成中文叫正則表達式。也不知道是誰翻譯過來的,聽起來就很嚴肅。彷佛翻譯成通用表達式更能傳達其精髓,若是你不怕夢見屈原的話。正則表達式

爲何叫通用表達式?由於它有一套和編程語言無關的文本匹配規則。不少語言都實現了正則表達式的文本匹配引擎,只不過在功能集合上略有不一樣。express

咱們要記住的是三點:編程

其一,正則表達式是用來提取文本的。編程語言

其二,正則表達式的表達能力強大到使人髮指。函數

其三,正則表達式的語法對初學者不友好。

另外,本專題只涉及JavaScript語言的正則表達式,其餘語言的規則可能略有不一樣。

我還爲各位讀者準備了一副宣傳語,應該能讓你心動(點贊)吧?

學一門前端工具,幾年就過期了。學正則表達式,受用一生。

普通字符

什麼叫普通字符?

當咱們寫a的時候,咱們指的就是a;當咱們寫的時候,咱們指的就是

'hello 😀 regex'.match(/😀/);
// ["😀", index: 6, input: "hello 😀 regex", groups: undefined]
複製代碼

這就是普通字符,它在正則中的含義就是檢索它自己。除了正則規定的部分字符外,其他的都是普通字符,包括各類人類語言,包括emoji,只要可以表達爲字符串。

開始與結束

^字符的英文是caret,翻譯成中文是脫字符。不要問我,又不是我翻譯的。它在正則中屬於元字符,一般表明的意義是文本的開始。說一般是由於當它在字符組中[^abc]另有含義。

什麼叫文本的開始?就是若是它是正則主體的第一個符號,那緊跟着它的字符必須是被匹配文本的第一個字符。

'regex'.match(/^r/);
// ["r", index: 0, input: "regex", groups: undefined]
複製代碼

問題來了,若是^不是正則的第一個符號呢?

'regex'.match(/a^r/);
// null
複製代碼

因此呀,關於它有三點須要注意:

  • 做爲匹配文本開始元字符的時候必須是正則主體的第一個符號,不然正則無效。
  • 它匹配的是一個位置,而不是具體的文本。
  • 它在其餘規則中有另外的含義。

$字符與^正好相反。它表明文本的結束,而且沒有其餘含義(實際上是有的,但不是在正則主體內)。一樣,它必須是正則主體的最後一個符號。

'regex'.match(/x$/);
// ["x", index: 4, input: "regex", groups: undefined]
複製代碼

^$特殊的地方在於它匹配的是一個位置。位置不像字符,它看不見,因此更不容易理解。

轉義

咱們如今已經知道$匹配文本的結束位置,它是元字符。可是若是我想匹配$自己呢?匹配一個美圓符號的需求再常見不過了吧。因此咱們得將它貶爲庶民。

\反斜槓就是幹這個的。

'price: $3.6'.match(/\$[0-9]+\.[0-9]+$/);
// ["$3.6", index: 7, input: "price: $3.6", groups: undefined]
複製代碼

上面的例子有點超綱了,超綱的部分先無論。

你能夠認爲\也是一個元字符,它跟在另外一個元字符後面,就能還原它原本的含義。

若是有兩個\呢?那就是轉義自身了。若是有三個\呢?咱們得分紅兩段去理解。以此類推。

普通字符前面跟了一個\是什麼效果?首先它們是一個總體,而後普通字符轉義後仍是普通字符。

帶反斜槓的元字符

通常來講,普通字符前面帶反斜槓仍是普通字符,可是有一些普通字符,帶反斜槓後反而變成了元字符。

要怪只能怪計算機領域的經常使用符號太少了。

元字符 含義
\b 匹配一個單詞邊界(boundary)
\B 匹配一個非單詞邊界
\d 匹配一個數字字符(digit)
\D 匹配一個非數字字符
\s 匹配一個空白字符(space)
\S 匹配一個非空白字符
\w 匹配一個字母或者一個數字或者一個下劃線(word)
\W 匹配一個字母、數字和下劃線以外的字符

你這麼聰明,確定一眼就看出來,大寫表明反義。對,就是這麼好記。

\b元字符

\b匹配的也是一個位置,而不是一個字符。單詞和空格之間的位置,就是所謂單詞邊界。

'hello regex'.match(/\bregex$/);
// ["regex", index: 6, input: "hello regex", groups: undefined]
'hello regex'.match(/\Bregex$/);
// null
複製代碼

所謂單詞邊界,對中文等其餘語言是無效的。

'jiangshuying gaoyuanyuan huosiyan'.match(/\bgaoyuanyuan\b/);
// ["gaoyuanyuan", index: 13, input: "jiangshuying gaoyuanyuan huosiyan", groups: undefined]
'江疏影 高圓圓 霍思燕'.match(/\b高圓圓\b/);
// null
複製代碼

因此\b翻譯一下就是^\w|\w$|\W\w|\w\W

\d元字符

\d匹配一個數字,注意,這裏的數字不是指JavaScript中的數字類型,由於文本全是字符串。它指的是表明數字的字符。

'123'.match(/\d/);
// ["1", index: 0, input: "123", groups: undefined]
複製代碼

\s元字符

\s匹配一個空白字符。

這裏須要解釋一下什麼是空白字符。

空白字符不是空格,它是空格的超集。不少人說它是\f\n\r\t\v的總和,其中\f是換頁符,\n是換行符,\r是回車符,\t是水平製表符,\v是垂直製表符。是這樣麼?

'a b'.match(/\w\s\w/);
// ["a b", index: 0, input: "a b", groups: undefined]
'a b'.match(/\w\f\w/);
// null
'a b'.match(/\w\n\w/);
// null
'a b'.match(/\w\r\w/);
// null
'a b'.match(/\w\t\w/);
// null
'a b'.match(/\w\v\w/);
// null
'a b'.match(/\w \w/);
// ["a b", index: 0, input: "a b", groups: undefined]
複製代碼

這樣說的人,明顯是沒有作過實驗。其實正確的寫法是空格\f\n\r\t\v的總和,集合裏面包含一個空格,可千萬別忽略了。誒,難道空格在正則中的寫法就是空一格麼,是的,就是這樣隨意。

這個集合中不少都是不可打印字符,估計只有\n是咱們的老朋友。因此,若是不須要區分空格和換行的話,那就大膽的用\s吧。

\w元字符

\w匹配一個字母或者一個數字或者一個下劃線。爲何要將它們放一塊兒?想想JavaScript中的變量規則,包括不少應用的用戶名都只能是這三樣,因此把它們放一塊兒挺方便的。

不過要注意,字母指的是26個英文字母,其餘的不行。

'正則'.match(/\w/);
// null
複製代碼

負陰抱陽

若是咱們將大寫和小寫的帶反斜槓的元字符組合在一塊兒,就能匹配任何字符。是的,不針對任何人。

'@regex'.match(/[\s\S]/);
// ["@", index: 0, input: "@regex", groups: undefined]
複製代碼

方括號的含義咱們先按下不表。

道生一

.在正則中的含義仙風道骨,它匹配換行符以外的任意單個字符。

若是文本不存在換行符,那麼.[\b\B][\d\D][\s\S][\w\W]是等價的。

若是文本存在換行符,那麼(.|\n)[\b\B][\d\D][\s\S][\w\W]是等價的。

'@regex'.match(/./);
// ["@", index: 0, input: "@regex", groups: undefined]
複製代碼

量詞

前面咱們一直在強調,一個元字符只匹配一個字符。即使強大如.它也只能匹配一個。

那匹配gooooogle的正則是否是得寫成/gooooogle/呢?

正則冷笑,並向你發射一個蔑視。

若是匹配的模式有重複,咱們能夠聲明它重複的次數。

量詞 含義
? 重複零次或者一次
+ 重複一次或者屢次,也就是至少一次
* 重複零次或者屢次,也就是任意次數
{n} 重複n次
{n,} 重複n次或者更屢次
{n,m} 重複n次到m次之間的次數,包含n次和m次

有三點須要注意:

  • ?在諸如匹配http協議的時候很是有用,就像這樣:/http(s)?/。它在正則中除了是量詞還有別的含義,後面會提到。

  • 咱們習慣用/.*/來匹配若干對咱們沒有價值的文本,它的含義是若干除換行符以外的字符。好比咱們須要文本兩頭的格式化信息,中間是什麼無所謂,它就派上用場了。不過它的性能可很差。

  • {n,m}之間不能有空格,空格在正則中是有含義的。

關於量詞最使人困惑的是:它重複什麼?

它重複緊貼在它前面的某個集合。第一點,必須是緊貼在它前面;第二點,重複一個集合。最多見的集合就是一個字符,固然正則中有一些元字符可以將若干字符變成一個集合,後面會講到。

'gooooogle'.match(/go{2,5}gle/);
// ["gooooogle", index: 0, input: "gooooogle", groups: undefined]
複製代碼

若是一個量詞緊貼在另外一個量詞後面會怎樣?

'gooooogle'.match(/go{2,5}+gle/);
// Uncaught SyntaxError: Invalid regular expression: /go{2,5}+gle/: Nothing to repeat
複製代碼

貪婪模式與非貪婪模式

前面提到量詞不能緊跟在另外一個量詞後面,立刻要👋👋打臉了。

'https'.match(/http(s)?/);
// ["https", "s", index: 0, input: "https", groups: undefined]
'https'.match(/http(s)??/);
// ["http", undefined, index: 0, input: "https", groups: undefined]
複製代碼

然而,個人臉是這麼好打的?

緊跟在?後面的?它不是一個量詞,而是一個模式切換符,從貪婪模式切換到非貪婪模式。

貪婪模式在正則中是默認的模式,就是在既定規則之下匹配儘量多的文本。由於正則中有量詞,它的重複次數多是一個區間,這就有了取捨。

緊跟在量詞以後加上?就能夠開啓非貪婪模式。怎麼省事怎麼來。

這裏的要點是,?必須緊跟着量詞,不然的話它本身就變成量詞了。

字符組

正則中的普通字符只能匹配它本身。若是我要匹配一個普通字符,可是我不肯定它是什麼,怎麼辦?

'grey or gray'.match(/gr[ae]y/);
// ["grey", index: 0, input: "grey or gray", groups: undefined]
複製代碼

方括號在正則中表示一個區間,咱們稱它爲字符組。

首先,字符組中的字符集合只是全部的可選項,最終它只能匹配一個字符。

而後,字符組是一個獨立的世界,元字符不須要轉義。

'$'.match(/[$&@]/);
// ["$", index: 0, input: "$", groups: undefined]
複製代碼

最後,有兩個字符在字符組中有特殊含義。

^在字符組中表示取反,再也不是文本開始的位置了。

'regex'.match(/[^abc]/);
// ["r", index: 0, input: "regex", groups: undefined]
複製代碼

若是我就要^呢?前面已經講過了,轉義。

-原本是一個普通字符,在字符組中搖身一變成爲連字符。

'13'.match(/[1-9]3/);
// ["13", index: 0, input: "13", groups: undefined]
複製代碼

連字符的意思是匹配範圍在它的左邊字符和右邊字符之間。

若是我這樣呢?

'abc-3'.match(/[0-z]/);
// ["a", index: 0, input: "abc-3", groups: undefined]
複製代碼
'xyz-3'.match(/[0-c]/);
// ["3", index: 4, input: "xyz-3", groups: undefined]
複製代碼
'xyz-3'.match(/[0-$]/);
// Uncaught SyntaxError: Invalid regular expression: /[0-$]/: Range out of order in character class
複製代碼

發現什麼了沒有?只有兩種字符是能夠用連字符的:英文字母和數字。並且英文字母能夠和數字連起來,英文字母的順序在後面。這和撲克牌1 2 3 4 5 6 7 8 9 10 J Q K是一個道理。

捕獲組與非捕獲組

咱們已經知道量詞是怎麼回事了,咱們也知道量詞只能重複緊貼在它前面的字符。

若是我要重複的是一串字符呢?

'i love you very very very much'.match(/i love you very +much/);
// null
'i love you very very very much'.match(/i love you v+e+r+y+ +much/);
// null
複製代碼

這樣確定是不行的。是時候請圓括號出山了。

'i love you very very very much'.match(/i love you (very )+much/);
// ["i love you very very very much", "very ", index: 0, input: "i love you very very very much", groups: undefined]
複製代碼

圓括號的意思是將它其中的字符集合打包成一個總體,而後量詞就能夠操做這個總體了。這和方括號的效果是徹底不同的。

並且默認的,圓括號的匹配結果是能夠捕獲的。

正則內捕獲

如今咱們有一個需求,匹配<div>標籤。

'<div>hello regex</div>'.match(/<div>.*<\/div>/);
// ["<div>hello regex</div>", index: 0, input: "<div>hello regex</div>", groups: undefined]
複製代碼

這很簡單。但若是我要匹配的是任意標籤,包括自定義的標籤呢?

'<App>hello regex</App>'.match(/<([a-zA-Z]+)>.*<\/\1>/);
// ["<App>hello regex</App>", "App", index: 0, input: "<App>hello regex</App>", groups: undefined]
複製代碼

這時候就要用到正則的捕獲特性。正則內捕獲使用\數字的形式,分別對應前面的圓括號捕獲的內容。這種捕獲的引用也叫反向引用

咱們來看一個更復雜的狀況:

'<App>hello regex</App><p>A</p><p>hello regex</p>'.match(/<((A|a)pp)>(hello regex)+<\/\1><p>\2<\/p><p>\3<\/p>/);
// ["<App>hello regex</App><p>A</p><p>hello regex</p>", "App", "A", "hello regex", index: 0, input: "<App>hello regex</App><p>A</p><p>hello regex</p>", groups: undefined]
複製代碼

若是有嵌套的圓括號,那麼捕獲的引用是先遞歸的,而後纔是下一個頂級捕獲。

正則外捕獲

'@abc'.match(/@(abc)/);
// ["@abc", "abc", index: 0, input: "@abc", groups: undefined]
RegExp.$1;
// "abc"
複製代碼

沒錯,RegExp就是構造正則的構造函數。若是有捕獲組,它的實例屬性$數字會顯示對應的引用。

若是有多個正則呢?

'@abc'.match(/@(abc)/);
// ["@abc", "abc", index: 0, input: "@abc", groups: undefined]
'@xyz'.match(/@(xyz)/);
// ["@xyz", "xyz", index: 0, input: "@xyz", groups: undefined]
RegExp.$1;
// "xyz"
複製代碼

RegExp構造函數的引用只顯示最後一個正則的捕獲。

另外還有一個字符串實例方法也支持正則捕獲的引用,它就是replace方法。

'hello **regex**'.replace(/\*{2}(.*)\*{2}/, '<strong>$1</strong>');
// "hello <strong>regex</strong>"
複製代碼

實際上它纔是最經常使用的引用捕獲的方式。

捕獲命名

這是ES2018的新特性。

使用\數字引用捕獲必須保證捕獲組的順序不變。如今開發者能夠給捕獲組命名了,有了名字之後,引用起來更加肯定。

'<App>hello regex</App>'.match(/<(?<tag>[a-zA-Z]+)>.*<\/\k<tag>>/);
// ["<App>hello regex</App>", "App", index: 0, input: "<App>hello regex</App>", groups: {tag: "App"}]
複製代碼

在捕獲組內部最前面加上?<key>,它就被命名了。使用\k<key>語法就能夠引用已經命名的捕獲組。

是否是很簡單?

一般狀況下,開發者只是想在正則中將某些字符當成一個總體看待。捕獲組很棒,可是它作了額外的事情,確定須要額外的內存佔用和計算資源。因而正則又有了非捕獲組的概念。

'@abc'.match(/@(abc)/);
// ["@abc", "abc", index: 0, input: "@abc", groups: undefined]
'@abc'.match(/@(?:abc)/);
// ["@abc", index: 0, input: "@abc", groups: undefined]
複製代碼

只要在圓括號內最前面加上?:標識,就是告訴正則引擎:我只要這個總體,不須要它的引用,你就別費勁了。從上面的例子也能夠看出來,match方法返回的結果有些許不同。

我的觀點:我以爲正則的捕獲設計應該反過來,默認不捕獲,加上?:標識後才捕獲。由於大多數時候開發者是不須要捕獲的,可是它又懶得加?:標識,會有些許性能浪費。

分支

有時候開發者須要在正則中使用或者

'高圓圓'.match(/陳喬恩|高圓圓/);
// ["高圓圓", index: 0, input: "高圓圓", groups: undefined]
複製代碼

|就表明或者。字符組其實也是一個多選結構,可是它們倆有本質區別。字符組最終只能匹配一個字符,而分支匹配的是左邊全部的字符或者右邊全部的字符。

咱們來看一個例子:

'我喜歡高圓圓'.match(/我喜歡陳喬恩|高圓圓/);
// ["高圓圓", index: 3, input: "我喜歡高圓圓", groups: undefined]
複製代碼

由於|是將左右兩邊一切兩半,而後匹配左邊或者右邊。因此上面的正則顯然達不到咱們想要的效果。這個時候就須要一個東西來縮小分支的範圍。誒,你可能已經想到了:

'我喜歡高圓圓'.match(/我喜歡(?:陳喬恩|高圓圓)/);
// ["我喜歡高圓圓", index: 0, input: "我喜歡高圓圓", groups: undefined]
複製代碼

沒錯,就是圓括號。

零寬斷言

正則中有一些元字符,它不匹配字符,而是匹配一個位置。好比以前提到的^$^的意思是說這個位置應該是文本開始的位置。

正則還有一些比較高級的匹配位置的語法,它匹配的是:在這個位置以前或以後應該有什麼內容。

零寬(zero-width)是什麼意思?指的就是它匹配一個位置,自己沒有寬度。

斷言(assertion)是什麼意思?指的是一種判斷,斷言以前或以後應該有什麼或應該沒有什麼。

零寬確定先行斷言

所謂的確定就是判斷有什麼,而不是判斷沒有什麼。

而先行指的是向前看(lookahead),斷言的這個位置是爲前面的規則服務的。

語法很簡單:圓括號內最左邊加上?=標識。

'CoffeeScript JavaScript javascript'.match(/\b\w{4}(?=Script\b)/);
// ["Java", index: 13, input: "CoffeeScript JavaScript javascript", groups: undefined]
複製代碼

上面匹配的是四個字母,這四個字母要知足如下條件:緊跟着的應該是Script字符串,並且Script字符串應該是單詞的結尾部分。

因此,零寬確定先行斷言的意思是:如今有一段正則語法,用這段語法去匹配給定的文本。可是,知足條件的文本不只要匹配這段語法,緊跟着它的必須是一個位置,這個位置又必須知足一段正則語法。

說的再直白點,我要匹配一段文本,可是這段文本後面必須緊跟着另外一段特定的文本。零寬確定先行斷言就是一個界碑,我要知足前面和後面全部的條件,可是我只要前面的文本。

咱們來看另外一種狀況:

'CoffeeScript JavaScript javascript'.match(/\b\w{4}(?=Script\b)\w+/);
// ["JavaScript", index: 13, input: "CoffeeScript JavaScript javascript", groups: undefined]
複製代碼

上面的例子更加直觀,零寬確定先行斷言已經匹配過Script一次了,後面的\w+卻仍是能匹配Script成功,足以說明它的零寬特性。它爲緊貼在它前面的規則服務,而且不影響後面的匹配規則。

零寬確定後行斷言

先行是向前看,那後行就是向後看(lookbehind)咯。

語法是圓括號內最左邊加上?<=標識。

'演員高圓圓 將軍霍去病 演員霍思燕'.match(/(?<=演員)霍\S+/);
// ["霍思燕", index: 14, input: "演員高圓圓 將軍霍去病 演員霍思燕", groups: undefined]
複製代碼

一個正則能夠有多個斷言:

'演員高圓圓 將軍霍去病 演員霍思燕'.match(/(?<=演員)霍.+?(?=\s|$)/);
// ["霍思燕", index: 14, input: "演員高圓圓 將軍霍去病 演員霍思燕", groups: undefined]
複製代碼

零寬否認先行斷言

確定是判斷有什麼,否認就是判斷沒有什麼咯。

語法是圓括號內最左邊加上?!標識。

'TypeScript Perl JavaScript'.match(/\b\w{4}(?!Script\b)/);
// ["Perl", index: 11, input: "TypeScript Perl JavaScript", groups: undefined]
複製代碼

零寬否認後行斷言

語法是圓括號最左邊加上?<!標識。

'演員高圓圓 將軍霍去病 演員霍思燕'.match(/(?<!演員)霍\S+/);
// ["霍去病", index: 8, input: "演員高圓圓 將軍霍去病 演員霍思燕", groups: undefined]
複製代碼

修飾符

正則表達式除了主體語法,還有若干可選的模式修飾符。

寫法就是將修飾符安插在正則主體的尾巴上。好比這樣:/abc/gi

g修飾符

gglobal的縮寫。默認狀況下,正則從左向右匹配,只要匹配到告終果就會收工。g修飾符會開啓全局匹配模式,找到全部匹配的結果。

'演員高圓圓 將軍霍去病 演員霍思燕'.match(/(?<=演員)\S+/);
// ["高圓圓", index: 2, input: "演員高圓圓 將軍霍去病 演員霍思燕", groups: undefined]
'演員高圓圓 將軍霍去病 演員霍思燕'.match(/(?<=演員)\S+/g);
// ["高圓圓", "霍思燕"]
複製代碼

i修飾符

iignoreCase的縮寫。默認狀況下,/z/是沒法匹配Z的,因此咱們有時候不得不這樣寫:/[a-zA-Z]/i修飾符能夠全局忽略大小寫。

不少時候咱們不在意文本是大寫、小寫仍是大小寫混寫,這個修飾符仍是頗有用的。

'javascript is great'.match(/JavaScript/);
// null
'javascript is great'.match(/JavaScript/i);
// ["javascript", index: 0, input: "javascript is great", groups: undefined]
複製代碼

m修飾符

mmultiline的縮寫。這個修飾符有特定起做用的場景:它要和^$搭配起來使用。默認狀況下,^$匹配的是文本的開始和結束,加上m修飾符,它們的含義就變成了行的開始和結束。

` abc xyz `.match(/xyz/);
// ["xyz", index: 5, input: "↵abc↵xyz↵", groups: undefined]
` abc xyz `.match(/^xyz$/);
// null
` abc xyz `.match(/^xyz$/m);
// ["xyz", index: 5, input: "↵abc↵xyz↵", groups: undefined]
複製代碼

y修飾符

這是ES2015的新特性。

ysticky的縮寫。y修飾符有和g修飾符重合的功能,它們都是全局匹配。因此重點在sticky上,怎麼理解這個粘連呢?

g修飾符不挑食,匹配完一個接着匹配下一個,對於文本的位置沒有要求。可是y修飾符要求必須從文本的開始實施匹配,由於它會開啓全局匹配,匹配到的文本的下一個字符就是下一次文本的開始。這就是所謂的粘連。

'a bag with a tag has a mag'.match(/\wag/g);
// ["bag", "tag", "mag"]
'a bag with a tag has a mag'.match(/\wag/y);
// null
'bagtagmag'.match(/\wag/y);
// ["bag", index: 0, input: "bagtagmag", groups: undefined]
'bagtagmag'.match(/\wag/gy);
// ["bag", "tag", "mag"]
複製代碼

有人確定發現了貓膩:你不是說y修飾符是全局匹配麼?看上面的例子,單獨一個y修飾符用match方法怎麼並非全局匹配呢?

誒,這裏說來就話長了。

長話短說呢,就涉及到y修飾符的本質是什麼。它的本質有二:

  • 全局匹配(先彆着急打我)。
  • 從文本的lastIndex位置開始新的匹配。lastIndex是什麼?它是正則表達式的一個屬性,若是是全局匹配,它用來標註下一次匹配的起始點。這纔是粘連的本質所在。

不知道大家發現什麼了沒有:lastIndex是正則表達式的一個屬性。而上面例子中的match方法是做用在字符串上的,都沒有lastIndex屬性,休怪人家工做不上心。

const reg = /\wag/y;
reg.exec('bagtagmag');
// ["bag", index: 0, input: "bagtagmag", groups: undefined]
reg.exec('bagtagmag');
// ["tag", index: 3, input: "bagtagmag", groups: undefined]
reg.exec('bagtagmag');
// ["mag", index: 6, input: "bagtagmag", groups: undefined]
複製代碼

我們換成正則方法exec,屢次執行,正則的lastIndex在變,匹配的結果也在變。全局匹配無疑了吧。

s修飾符

這是ES2018的新特性。

s不是dotAll的縮寫。s修飾符要和.搭配使用,默認狀況下,.匹配除了換行符以外的任意單個字符,然而它尚未強大到無所不能的地步,因此正則索性給它開個掛。

s修飾符的做用就是讓.能夠匹配任意單個字符。

ssingleline的縮寫。

` abc xyz `.match(/c.x/);
// null
` abc xyz `.match(/c.x/s);
// ["c↵x", index: 3, input: "↵abc↵xyz↵", groups: undefined]
複製代碼

u修飾符

這是ES2015的新特性。

uunicode的縮寫。有一些Unicode字符超過一個字節,正則就沒法正確的識別它們。u修飾符就是用來處理這些不常見的狀況的。

'𠮷'.match(/^.$/);
// null
'𠮷'.match(/^.$/u);
// ["𠮷", index: 0, input: "𠮷", groups: undefined]
複製代碼

𠮷,與同義。

筆者對Unicode認識尚淺,這裏不過多展開。


本文是『horseshoe·Regex專題』系列文章之一,後續會有更多專題推出

GitHub地址:github.com/veedrin/hor…

博客地址(文章排版真的很漂亮):matiji.cn

若是以爲對你有幫助,歡迎來GitHub點Star或者來個人博客親口告訴我

Regex專題一覽

👉 語法

👉 方法

👉 引擎

相關文章
相關標籤/搜索