正則表達式匹配方法 match() -- Vue正則解析template

最近看到vue源碼的模板解析,parse 中主要就是用正則去解析template然後生成ast抽象樹。這則匹配用到最多的就是match。

match([string] | [RegExp]) 

這裏主要說正則表達式

1、返回值:Array/null

2、不使用g全局匹配時

var str='2019shanghai=nihao !!'
str.match(/\w[i]/)

 

可以看出會找到首次匹配的字符串立馬返回,返回的數組有4項

0:匹配到的字符串                                     group:undefined,這表示當前的正則表達式沒使用分組

index :首次匹配上的子串的起始下標。 input:表示源字符串

 

3、使用g全局匹配

如果要找所有匹配的字符串,需要加g

var str='2019shanghai=nihao !!'
str.match(/\w[i]/g)
=>["ai", "ni"]

 很明顯返回了兩個匹配的選項,但少了不加g全局匹配時兩個項(index,group)

4、使用分組 

  ①使用分組,且不使用g全局匹配

語義:找出首次匹配等號前後都是英文字母的字符串,並返回分組內匹配的字符串。

var str='2019shanghai=nihao !! my_age=age18'
str.match(/([A-Za-z]*)(=)[A-Za-z]+/)

數組第一個元素是正則找到的最長的匹配,剩下的2個元素是對應()分組裏面的正則匹配到的字符串。

而且發現只會匹配到第一組,就會返回結果。過去繼續查找後續的匹配項。這和原先不使用分組是不使用g是一樣的。

   ②使用分組(配合使用?:---匹配但不捕獲),且不使用g全局匹配

語義:找出首次匹配等號前後都是英文字母的字符串,並返回分組內匹配的字符串(忽略含?:的分組)。

var str='2019shanghai=nihao !! my_age=age18'
str.match(/([A-Za-z]*)(?:=)[A-Za-z]+/)

相比於①少了一個元素=,因爲在分組(=)裏面加了?: 其他的都不變,匹配依然是一樣的匹配,只是不展示在該分組內的匹配對應元素。

   ③使用分組,且使用g全局匹配

語義:找出所有匹配等號前後都是英文字母的字符串。

var str='2019shanghai=nihao !! my_age=age18'
str.match(/([A-Za-z]*)(=)[A-Za-z]+/g)

很明顯分組內匹配到的都不會展示,只會展示最長的能匹配的字符串集合。

5、vue源碼裏template的正則分析:

首先vue源碼中templete模板解析的原理是,通過正則依次解析template字符串,並通過advance截取調對應的字符串,匹配類型有 :起始標籤,結束標籤、註釋、Doctype、條件註釋等。其中起始標籤內,還會匹配標籤內的屬性,表達式等。

匹配起始標籤:

const ncname = '[a-zA-Z_][\\w\\-\\.]*'

const qnameCapture = `((?:${ncname}\\:)?${ncname})`

const startTagOpen = new RegExp(`^<${qnameCapture}`)

html.match(startTagOpen)

等價於 html.match(/^<((?:[a-zA-Z_][\w\-\.]*\:)?[a-zA-Z_][\w\-\.]*)/)

[a-zA-Z_] :一個(字母、下劃線)組成的字符串

[\w\-\.]* :字母、下劃線、中劃線、小數點組成的字符串0個或以上個

\:  :以冒號結尾的字符串

? :0個或一個

[a-zA-Z_]  :一個(字母、下劃線)組成的字符串

[\w\-\.]* :0個或以上(字母,數字,中劃線,下劃線,小數點)組成的字符串

大概意思:^<  以<起始,後面緊跟的字符串必須以字母或下劃線開頭,後面可以是字母,下劃線,中劃線,小數點組合而成,但最多可以出現一次冒號,且冒號不是在最後。

注:裏面的?:主要是爲了避免多次分組出現在匹配中,因爲存在兩個分組的嵌套。

 

匹配起始標籤內的屬性,表達式

 const attribute = /^\s*([^\s"'<>\/=]+)(?:\s*(=)\s*(?:"([^"]*)"+|'([^']*)'+|([^\s"'=<>`]+)))?/

attr = html.match(attribute))

// ^\s* --0個或者更多的空白字符開頭

// ([^\s"'<>\/=]+) 不是空字符、"'<>/=的符號

// (?:\s*(=)\s* 匹配等號並捕獲,且匹配前後的空白字符但不不捕獲

// (?:"([^"]*)"+|'([^']*)'+|([^\s"'=<>`]+))匹配非"的字符並捕獲,且匹配前後的"但不不捕獲 | 匹配非'的字符並捕獲,且匹配前後的'但不不捕獲 | 匹配非空白字符 " ' = < > 的字符並捕獲

如上圖,html是通過advance函數截取剩下的template,返回的是首次匹配的數組,數組1,2,3,4,5分別是分組裏正則匹配的字符串

在Vue源碼中通過循環正則匹配取出裏面的屬性鍵值對,放入Ast抽象樹中。

模板解析的其他正則也是類似的如下是裏面的正則

const startTagClose = /^\s*(\/?)>/  --------------起始閉合標籤

const endTag = new RegExp(`^<\\/${qnameCapture}[^>]*>`)   ----結束標籤

const doctype = /^<!DOCTYPE [^>]+>/i   -----doctype標籤

const comment = /^<!\--/       ----------註釋標籤

const conditionalComment = /^<!\[/     -----------條件註釋

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章