手摸手快速入门 正则表达式 (Vue源码中的使用)
vue2源码
在 vue2
源码的 src\compiler\parser\html-parser.js
文件中
里面有大量的正则表达式,如下图
可以看到非常的长,不是我说,就前几行,如果没有相关的 正则表达式 的工具,我可能就被劝退了😭
这里先推荐一个 可视化正则表达式 工具,非常好用!
回归正题,那上面这么多 正则表达式 代表的什么含义呢?
- 它们主要是用来匹配我们的
html
模板* 之后会将匹配到的内容,转化成AST
语法树可以看到这些是很重要的,
我们接下来分析理解一下里面的相关内容。
1. startTagOpen
它是 html
: 开始标签的 左边 部分
而生成这个 正则表达式 的代码有四行
const unicodeRegExp = /a-zA-Z\u00B7\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u037D\u037F-\u1FFF\u200C-\u200D\u203F-\u2040\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD/
const ncname = `[a-zA-Z_][\\-\\.0-9_a-zA-Z${unicodeRegExp.source}]*`
const qnameCapture = `((?:${ncname}\\:)?${ncname})`
const startTagOpen = new RegExp(`^<${qnameCapture}`)
它的作用,或者说它能够匹配到的内容
- 标签开始符号
<
,当然后面会跟着相关的标签内容,下面会分析有哪些标签内容* 但是注意 没有 标签结束符>
### 1.1 ncname
在知道它匹配什么内容了之后,我们看一下 ncname
,
可以看到它是一个 字符串,里面有 unicodeRegExp.source
这就引出我们第一个知识点,正则的 RegExp.source
可以看下它的 MDN 介绍,我们知道它这个属性的作用是
- 获取正则表达式里面的内容* 即获取到 两侧的斜杠
/.../
之间的内容即,我们得到ncname
这个字符串的值为
const ncname = '[a-zA-Z_][\\-\\.0-9_a-zA-Za-zA-Z\\u00B7\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u203F-\\u2040\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD]*'
转化为正则后
const newNcanme = new RegExp(ncname)/[a-zA-Z_][\-\.0-9_a-zA-Za-zA-Z\u00B7\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u037D\u037F-\u1FFF\u200C-\u200D\u203F-\u2040\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD]*/
我们将这个正则表达式放到 可视化工具 中,得到下图
可以看到它能够匹配,开头为 a-z
、 A-Z
、_
中的其中一个,后面则是零次或多次
1.2 qnameCapture
知道 ncname
匹配的内容是什么之后,我们接下来我们看下 qnameCapture
const qnameCapture = `((?:${ncname}\\:)?${ncname})`'((?:[a-zA-Z_][\\-\\.0-9_a-zA-Za-zA-Z\\u00B7\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u203F-\\u2040\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD]*\\:)?[a-zA-Z_][\\-\\.0-9_a-zA-Za-zA-Z\\u00B7\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u203F-\\u2040\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD]*)'
转化为正则,并将其放入 可视化工具 中
const newQnameCapture =new RegExp(qnameCapture)/((?:[a-zA-Z_][\-\.0-9_a-zA-Za-zA-Z\u00B7\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u037D\u037F-\u1FFF\u200C-\u200D\u203F-\u2040\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD]*\:)?[a-zA-Z_][\-\.0-9_a-zA-Za-zA-Z\u00B7\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u037D\u037F-\u1FFF\u200C-\u200D\u203F-\u2040\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD]*)/
从 代码 和 图,一起分析,可以知道
- 将它们整体作为了一个 组* 又将前面第一部分作为 非捕获分组,虽然需要匹配内容,但是我们并不需要它的一个结果
(?:表达式)
* 在表达式后面,可以看到有一个:
字符,说明,如果前面这个匹配, 那么后面必须跟上一个:
字符才算成功* 在前面的分组后面紧跟 重复 字段?
,说明它能够匹配 0次 或 1 次* 最后面则就是ncname
,上面已经分析过了。### 1.3 startTagOpen
最后就是我们的 startTagOpen
这个其实很好理解,就是在前面加上了一个元字符 ^
和 <
代表的意思就是,必须是 <
开头
- 但是注意哦,并没有说结尾* 结尾则是后面要讲的
startTagClose
来匹配的这里我们依然进行一波 处理,看下结果
const startTagOpen = new RegExp(`^<${qnameCapture}`)/^<((?:[a-zA-Z_][\-\.0-9_a-zA-Za-zA-Z\u00B7\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u037D\u037F-\u1FFF\u200C-\u200D\u203F-\u2040\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD]*\:)?[a-zA-Z_][\-\.0-9_a-zA-Za-zA-Z\u00B7\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u037D\u037F-\u1FFF\u200C-\u200D\u203F-\u2040\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD]*)/
1.4 总结
我们知道了 startTagOpen
的一个作用
就是用来以匹配 <
开头,后面跟上标签,标签开头必须是 a-z
、A-Z
、_
中的一个
例如:<div
、<xxx:yyy
值得注意:它是没有结束的右尖括号 >
的
2. startTagClose
它是 html
: 开始标签的 右边 部分
先看下正则表达式
const startTagClose = /^\s*(\/?)>/
这个主要是匹配 标签结束符 >
,当然还包括一些其它内容
- 前面可能有空格,* 可能有
/
字符例如<div>
或者 单标签<img />
的 右边部分>
和/>
下面是它的 正则表达式 图,可以看到很简单
3. endTag
它是 html
: 整个 结束标签
例如 </div>
、 </xxx:yyy>
这里看下它的 正则表达式 以及 图
const endTag = new RegExp(`^<\\/${qnameCapture}[^>]*>`)/^<\/((?:[a-zA-Z_][\-\.0-9_a-zA-Za-zA-Z\u00B7\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u037D\u037F-\u1FFF\u200C-\u200D\u203F-\u2040\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD]*\:)?[a-zA-Z_][\-\.0-9_a-zA-Za-zA-Z\u00B7\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u037D\u037F-\u1FFF\u200C-\u200D\u203F-\u2040\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD]*)[^>]*>/
可以看到 结束标签 的 开头 必须是 </
,结尾 必须是 >
中间的内容就跟上面分析的一样
但是结尾前边有一个 非 >
的区间,就有点疑问了!
- 虽然这个含义很好理解,但是为什么加这个呢?* 仅仅只是为了说明,前面只要不是
>
都行?但是前面已经有ncanme
了。* 所以这个字符的真正含义,有没有大佬出来解答下😁4. attribute
看这个单词的含义,我们都知道是 属性 的意思
因为后面还有 dynamicArgAttribute
所以我们叫 attribute
,为 普通的 html 属性
那我们来分析下这个 正则表达式 的含义吧
const attribute = /^\s*([^\s"'<>\/=]+)(?:\s*(=)\s*(?:"([^"]*)"+|'([^']*)'+|([^\s"'=<>`]+)))?/
害,光看这么长,都有点脑瓜子嗡嗡的😵💫
顺便放到工具中,得到下图
4.1 正则分析 - 1
可以看到一上去,前面可以匹配一些空格 \s*
之后遇到 第一个分组
-
里面是一个 区间,因为开头是
^
,说明是一个取反操作* 里面不能是 (空格、"
、'
、<
、>
、/
、=
)* 并且后面有一个 重复 字符+
,说明必须匹配一次以上往后看,是 第二个分组 -
不过这个分组是一个 非捕获分组
(?:表达式)
* 而且这个它后面,紧跟一个 重复 字符?
,说明匹配0
次或1
次到这里我们先暂停下,
通过上面的分析,我们可以大概知道,它能够匹配的属性是什么
它能够匹配 单个属性 ,例如:
<button disabled>
这里面的disabled
属性
4.2 正则分析 - 2
我们接着分析 非捕获分组 这一大段里面的内容 (红框部分)
/(?:\s*(=)\s*(?:"([^"]*)"+|'([^']*)'+|([^\s"'=<>`]+)))/
我们可以看到有个小的分组,里面是 =
字符,左右两边都是 \s*
说明
=
左右两边 可以有 空格 出现,但是平时我们都是紧贴着的是因为
Eslint
给我们提示了,而vue
本身是支持=
左右两边 有空格的。
我们继续分析
可以看到又是一个 非捕获分组,里面的内容通过 或运算符 |
连接
"([^"]*)"+
说明了 可以是 双引号*'([^']*)'+
说明了 可以使 单引号* 最后则表示,匹配非 空格、"
、'
、=
、<
、>
、**`**通过第二段分析,我们直接说一下它能够匹配到的内容是什么
例如:
class = "aaa"
、class="aaa"
*style = 'color:red;'
、style='color:red;'
* 第三个,其实没找到很好的例子,希望有大佬来解惑🎁### 4.3 总结
总结下,上面这两点,其实它这个匹配的内容是
- 无
=
号* 例如<button disabled
中的disabled
这类 - 有
=
号* 例如<button style="" class=''
中的"
或者'
这类* 当然,=
号 的左右两边都可以有空格5.dynamicArgAttribute
上面我们说了 普通的 html
属性
下面说一下 vue
的 动态属性
用过 vue
都知道 动态属性,就是在普通属性前面加一些 符号
,例如
v-xxx=
*:xxx=
*@xxx=
*#xxx=
这个我也是看完源码后,才知道,还有这么个符号(表示根本没用过…)* 而它呢,是v-slot
的简写
当然,我们这里还是要分析下它的 正则表达式
/^\s*((?:v-[\w-]+:|@|:|#)\[[^=]+\][^\s"'<>\/=]*)(?:\s*(=)\s*(?:"([^"]*)"+|'([^']*)'+|([^\s"'=<>`]+)))?/
并且得到如下图:
这里我将它与 普通 html
属性 的区别,用红色的框 框起来了
5.1 正则分析 - 1
(?:v-[\w-]+:|@|:|#)
是一个 非捕获分组,而它匹配到的内容为
v-
后面紧跟上 区间,区间 里面包含\w
和-
*\w
是能够匹配 字母、数字、下划线( _ ) 、中文* 而 区间 后面,有个重复+
,说明至少匹配区间里面的内容一次* 最后跟上一个:
字符*@
*:
*#
### 5.2 正则分析 - 2
\[[^=]+\]
这个很简单了
- 首先是 转义字符
\
帮我们将[
进行了转义* 之后是一个 区间,但是第一个字符是^
,说明进行了 取反 的操作* 也就是 除了=
外的 任意字符* 后面有个 重复字符+
,至少匹配一次* 最后是 转义后的]
### 5.3 总结
通过上面的分析,我们能够得到这个 正则表达式 可以匹配的内容是
下面是大概的例子
<div v-bind:[disabled]="true"
、简写:[disabled]="true"
*<div v-on:[click]="xxxFunc"
、 简写@[click]="xxxFunc"
*<div v-slot:[xxx]="yyy"
、 简写#[xxx]="xxxFunc"
可以看到,匹配的内容,与我们平时写法有区别的。
6. doctype
其实这个大家熟悉也陌生
这个是我们 html
页面中,最上面的声明部分,
它的作用是告知 web
浏览器页面使用 哪种 html
版本
目前我们经常使用的是:
<!DOCTYPE html>
其它的情况,其实也没怎么见过
接下来看下正则吧
const doctype = /^<!DOCTYPE [^>]+>/i
-
首先是 元字符 的
^
开头,后面必须是<!DOCTYPE
* 后面[^>]+
, 因为 区间 的开头是^
,说明进行了取反操作* 也就是能够匹配处理>
以外,其它任意字符* 最后是 重复 的+
,至少匹配一次* 然后是>
结尾* 当然,我们看到后面还有个 修饰符i
,不区分大小写它这个意思就是能够 匹配 我们html
页面中 -
最开头的
<!DOCTYPE xxxxxx yyyy>
这个声明* 或者小写的<!doctype xxxxxx yyyy>
都可以7. comment
const comment = /^<!\--/
这个是匹配我们的 html
中,注释的 开头,也就是 <!--
- 元字符 的
^
开头,后面紧跟<!--
这个较容易理解,我们直接下一个
8. conditionalComment
首先这个名字是,条件注释 的意思
其次,这个使用的场景,目前搜到的,是为了判断 IE
浏览器版本时用的
- 平时很少见
看下 正则表达式
const conditionalComment = /^<!\[/
与上面的 comment
很相似,就不再做分析
说一下,它匹配到的内容: <
最后
最近找到一个VUE的文档,它将VUE的各个知识点进行了总结,整理成了《Vue 开发必须知道的36个技巧》。内容比较详实,对各个知识点的讲解也十分到位。
有需要的小伙伴,可以点击下方卡片领取,无偿分享
相关文章:

手摸手快速入门 正则表达式 (Vue源码中的使用)
vue2源码 在 vue2 源码的 src\compiler\parser\html-parser.js 文件中 里面有大量的正则表达式,如下图 可以看到非常的长,不是我说,就前几行,如果没有相关的 正则表达式 的工具,我可能就被劝退了😭 这里…...

TCP/IP网络协议族分成及其每层作用
1、可以分为应用层、传输层、网络层、链路层 2、各层的作用 应用层(可以想象成是快递打包过程) 决定了向用户提供应用服务时通信的活动,将要进行的操作或者数据进行一个打包。 传输层(可以理解为选择顺丰、圆通等快递公司) 提供数据传输的方…...
041、子序列类型问题(labuladong)
子序列类型问题 一、经典动态规划:编辑距离 基于labuladong的算法网站,经典动态规划:编辑距离; 总结: 一般来说涉及到两个字符串的问题,需要依赖上一次的各种操作,一般使用dp tableÿ…...

linux系统开机文段释义
第一段Version 2.01.1204. Copyright (C) 2010American Megatrends, Inc.Press <DEL> or <F2> to entersetup. Press <F7> for BBS POPUP Menu.设备上电,提示按DEL键或者F2键进入BIOS设置。按F8可以调出启动设备列表,可以选择性的启动…...

抽奖动画大转盘抽奖思路与做法
抽奖是各类营销活动中最常见的一种形式,本产品需求大致如下:转盘周围跑马灯交替闪烁,点击抽奖,大转盘旋转,调用接口获取抽奖结果,大转盘指针指向对应的奖品。高保如下图12.整体思路本需求要求跑马灯交替闪烁…...
Java实现 - 华为2016研发工程师编程题
文章目录删数字符集合数独删数 题目描述 有一个数组 a[N] 顺序存放 0 ~ N-1 ,要求每隔两个数删掉一个数,到末尾时循环至开头继续进行,求最后一个被删掉的数的原始下标位置。以 8 个数 (N7) 为例 :{ 0,1,2…...
nginx的七层负载均衡
文章目录一、负载均衡介绍二、nginx的配置文件三、实验过程总结一、负载均衡介绍 四层负载均衡 所谓四层负载均衡是指OSI七层模型中的传输层, 那么传输层Nginx已经支持TCP/IP的控制, 所以只需要对客户端的请求进行TCP/IP协议的包转发就可以实现负载, 那么他的好处是性能非常快,…...

信息加密技术
介绍信息加密 信息加密是实现数据保密性的手段。 信息加密(Encryption)是将明文信息转换为密文信息,使之在缺少特殊信息时不可读的过程。只有拥有解密方法的对象,经由解密过程,才能将密文还原为正常可读的内容。 现…...

RS485通信总线详解
RS485 总线详解 RS-485 是美国电子工业协会(EIA)在 1983 年批准了一个新的平衡传输标准(Balanced Transmission Standard)也称作差分,EIA 刚开始将 RS(Recommended Standard)做为标准的前缀&am…...

罗技LogitechFlow技术--惊艳的多电脑切换体验
作者:Eason_LYC 悲观者预言失败,十言九中。 乐观者创造奇迹,一次即可。 一个人的价值,在于他所拥有的。所以可以不学无术,但不能一无所有! 技术领域:WEB安全、网络攻防 关注WEB安全、网络攻防。…...

社招中级前端笔试面试题总结
HTTP世界全览 互联网上绝大部分资源都使用 HTTP 协议传输;浏览器是 HTTP 协议里的请求方,即 User Agent;服务器是 HTTP 协议里的应答方,常用的有 Apache 和 Nginx;CDN 位于浏览器和服务器之间,主要起到缓存…...
东南大学研究生上学期英语期末总结
写在前面 作者:夏日 博客地址:https://blog.csdn.net/zss192 本文为东南大学研究生英语上学期期末总结,内容为根据老师所发 PPT 总结得来 相关资料: 点我查看 题型说明 Module 1 International Conference 50% 题型范围&am…...

leaflet 删除所有的marker图层,保留其他图层(085)
第085个 点击查看专栏目录 本示例的目的是介绍演示如何在vue+leaflet项目中清除所有的marker图层,保留其他图层,详情请参考源代码。这里面主要用到了(layer instanceof L.Marker ,注意 L.Marker中Marker首字母要大写。 直接复制下面的 vue+leaflet源代码,操作2分钟即可运行…...

双因素方差分析全流程
上篇文章讲述了“单因素方差分析全流程总结”,单因素方差分析只是考虑了一个自变量(定类)与一个因变量(定量)之间的关系,但是在实际问题研究中可能研究两个或者几个因素与因变量之间的关系,例如…...

微信公众号抽奖怎么做_分享微信抽奖小程序制作的好处
在H5游戏中,抽奖是最受消费者喜爱的模式之一。将H5微信抽奖活动结合到营销中,可以带来意想不到的效果,带流量和曝光率,所以许多企业也会在做活动时添加上不同类型的H5微信抽奖活动。编辑那么,新手怎么搭建微信抽奖活动…...

逻辑回归—分类问题的操作顺序
对于二元分类问题来说,分类的结果和数据的特征之间仍呈现相关关系,但是y的值不再是连续的,是0~1的跃迁。但是在这个过程中,什么仍然是连续的呢?”是概率,概率是逐渐升高的,当达到一个…...

查询服务器tns文件路径,oracle数据库tns配置方法详解
查询服务器tns文件路径,oracle数据库tns配置方法详解 TNS简要介绍与应用 Oracle中TNS的完整定义:transparence Network Substrate透明网络底层, 监听服务是它重要的一部分,不是全部,不要把TNS当作只是监听器。 TNS是Oracle Net…...

【数据结构】链表
目录 数据结构之链表:: SList.h 1.链表的概念及结构 2.链表的分类 SList.c 3.动态申请一个结点 4.单链表打印 5.单链表销毁 6.单链表头插 7.单链表头删 8.单链表尾插 9.单链表尾删 10.单链表查找 11.单链表在pos之前插入…...

一文讲明Hystrix熔断器
前言 解决问题: 主要防止服务器集群发生雪崩, 起到对服务器的保护作用 GitHub地址:https://github.com/Netflix/Hystrix/wiki 1 Hystrix是什么 1.1 分布式系统面临的问题 复杂分布式体系结构中的应用程序有数十个依赖关系,每个依赖关系在某些时候将不…...
第12篇:Java类核心构成要素分析
目录 1、Java类构成要素 1.1 如何定义类 1.2 如何定义变量 1.2.1 类变量 1.2.2 实例变量...

Unity版本使用情况统计(更新至2025年5月)
UWA发布|本期UWA发布的内容是Unity版本使用统计(第十六期),统计周期为2024年11月至2025年5月,数据来源于UWA网站(www.uwa4d.com)性能诊断提测的项目。希望给Unity开发者提供相关的行业趋势作为参…...

人机融合智能 | 可穿戴计算设备的多模态交互
可穿戴计算设备可以对人体以及周围环境进行连续感知和计算,为用户提供随时随地的智能交互服务。本章主要介绍人机智能交互领域中可穿戴计算设备的多模态交互,阐述以人为中心的智能穿戴交互设计目标和原则,为可穿戴技术和智能穿戴交互技术的设计提供指导,进而简述支持智能穿戴交…...
MongoDB检查慢查询db.system.profile.find 分析各参数的作用
db.system.profile.find() 是分析 MongoDB 性能的关键工具,其返回的文档包含丰富的性能指标。下面是对各参数的详细解释和优化建议: {"op": "query", // 操作类型(query/update/remove)"ns": "test.users", // 命名…...
【win | 自动更新关闭】win11
利用本地组策略编辑器 对于Windows 11专业版或更高版本的用户,可以利用本地组策略编辑器来完全关闭自动更新。按下“WinR”键,输入“gpedit.msc”并回车。在本地组策略编辑器中,依次展开“计算机配置”>“管理模板”>“Windows组件”&…...

小黑一层层削苹果皮式大模型应用探索:langchain中智能体思考和执行工具的demo
引言 小黑黑通过探索langchain源码,设计了一个关于agent使用工具的一个简化版小demo(代码可以跑通),主要流程: 1.问题输入给大模型。 2.大模型进行思考,输出需要执行的action和相关思考信息。 3.通过代理&…...

手机号在网状态查询接口如何用PHP实现调用?
一、什么是手机号在网状态查询接口 通过精准探测手机号的状态,帮助平台减少此类问题的发生,提供更个性化的服务或进行地域性营销 二、应用场景 1. 金融风控 通过运营商在网态查询接口,金融机构可以核验贷款申请人的手机状态,拦…...

C#子线程更新主线程UI及委托回调使用示例
1.声明线程方法 2.线程中传入对象 3.声明委托与使用 声明委托对象 委托作为参数传入方法 4.在线程中传入委托 5.调用传入的委托...
如何用 pnpm patch 给 element-plus 打补丁修复线上 bug(以 2.4.4 修复 PR#15197 为例)
背景 在实际项目开发中,依赖的三方库(如 element-plus)难免会遇到 bug。有时候官方虽然已经修复,但新版本升级成本高,或者有兼容性风险。这时,给依赖打补丁是最优雅的解决方案之一。 本文以 element-plus…...

中国移动6周年!
基站超过250万个 网络规模全球最大、质量最优 覆盖全国96%人口 在全国率先实现乡乡双千兆 服务用户超5.7亿 网络上下行均值接入速率均居行业首位 行业应用快速推广,数量超5万个 3CC、RedCap、通感一体、 无线AI改造等技术成熟商用 客户品牌持续升级&#x…...

获取 OpenAI API Key
你可以按照以下步骤来获取 openai.api_key,用于调用 OpenAI 的 GPT-4、DALLE、Whisper 等 API 服务: 🧭 获取 OpenAI API Key 的步骤: ✅ 1. 注册或登录 OpenAI 账号 打开 https://platform.openai.com/ 使用你的邮箱或 Google/…...