最近看到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 = /^<!\[/ -----------條件註釋