手摸手快速入门 正则表达式 (Vue源码中的使用)

news2024/12/26 11:55:38

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-zA-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-zA-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 很相似,就不再做分析

说一下,它匹配到的内容: <![

9.encodedAttrWithNewLines

encodedAttrencodedAttrWithNewLines

const encodedAttr = /&(?:lt|gt|quot|amp|#39);/g
const encodedAttrWithNewLines = /&(?:lt|gt|quot|amp|#39|#10|#9);/g 

可以看到这两个 正则表达式 实在是太相似了,所以放到一起讲解下

其实它的匹配内容很简单

但是呢它的作用,我大概感觉可能跟 编解码 有关,具体的作用则需要通读一下源码才能了解。

这里就靠评论区大佬们,来解答这两个 正则表达式 的真正作用了🎁

我们这里还是分析下 正则表达式

  • 首先是一个 & 符号,后面则是一个 非捕获分组,* 里面要么是 ltgtquotamp#39#10#9 中的任意一个* 最后是一个 ; 分号 结尾可以看到它与 decodingMap 里面的内容很相关,所以我分析是跟 编解码 有关。

总结

这是最后一期 正则表达式

通过上面一系列的 正则表达式 的学习,以及 实战案例,还有 分析源码 中的使用

相信小伙伴们在 日常项目 ,或者 看源码时 ,不会再被 正则表达式 劝退了

愿世间再无 正则分析师

最后

最近找到一个VUE的文档,它将VUE的各个知识点进行了总结,整理成了《Vue 开发必须知道的36个技巧》。内容比较详实,对各个知识点的讲解也十分到位。



有需要的小伙伴,可以点击下方卡片领取,无偿分享

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/360652.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

反沙箱CobaltStrike木马加载器分析

前言 近日&#xff0c;笔者参加了浙江护网&#xff0c;在攻击队停止攻击的那一天凌晨&#xff0c;Windows服务器被攻破大量失分&#xff0c;早晨溯源时拿到了这一份名为chrome.exe的木马样本。 木马HASH SHA256:7fbe93d7c29b4ea4ce918f3d16a74d2930120f44d00862bdc0a1f82899…

ubuntu server系统树莓派安装mysql8.0开启远程访问

文章目录前言博客一、安装mysql8.0二、创建一个远程访问的新用户三、在MySQL配置文件中启用远程访问。四、navicat15连接mysql8.0返回10061chatgpt回复前言 百度了半天没解决&#xff0c;问了下chatgpt成功解决了…… 博客 一、安装mysql8.0 确认MySQL 8.0服务器已安装并正在…

【ESP32-S3】Pycharm 使用 microPython 教程(避坑)

一、下载Pycharm等操作 1.百度云下载链接 链接&#xff1a;https://pan.baidu.com/s/1tkbMzS5B_v-Cn4WQlTqS3Q?pwd0108 提取码&#xff1a;0108 2.安装 按照压缩包中的教程来&#xff0c;你懂的。 二、配置microPython环境 1.安装 microPython 插件 1.1 File > Sett…

【云原生】k8s之Yaml文件详解

一、K8S支持的文件格式 kubernetes支持YAML和JSON文件格式管理资源对象。 JSON格式&#xff1a;主要用于api接口之间消息的传递YAML格式&#xff1a;用于配置和管理&#xff0c;YAML是一种简洁的非标记性语言&#xff0c;内容格式人性化&#xff0c;较易读 1、yaml和json的主…

企业级信息系统开发学习笔记1.5 初探Spring AOP

文章目录零、本讲学习目标一、Spring AOP&#xff08;一&#xff09;AOP基本含义&#xff08;二&#xff09;AOP基本作用&#xff08;三&#xff09;AOP与OOP对比&#xff08;四&#xff09;AOP使用方式&#xff08;五&#xff09;AOP基本概念二、提出游吟诗人唱赞歌任务&#…

手把手教你做插件(2)模块大串联

0&#xff0c;前言 这篇文章笔记比较简略&#xff0c;大部分的操作都是和上一篇文章重复了&#xff0c;建议先看上一节文章&#xff0c;直达电梯&#xff1a;UE4 手把手教你做插件&#xff08;1&#xff09; 从代码引用插件_asiwxy的博客-CSDN博客UE4 手把手教你创建插件https:…

Windows10神州网信政府版麦克风、摄像头的使用

Windows10神州网信政府版默认麦克风摄像头是禁用状态&#xff0c;此禁用状态符合版本规定。 在录课和直播过程中&#xff0c;如果需要使用麦克风和摄像头的功能&#xff0c;可以这样更改&#xff1a; 1、鼠标右键点击屏幕左下角的开始菜单图标&#xff0c;选择windows中的“运…

[6/101] 101次软件测试面试之经典面试题剖析

01、自我介绍答&#xff1a;大家好&#xff0c;我是一名软件测试工程师&#xff0c;但我更喜欢称自己为“软件bug捕手”。我相信&#xff0c;软件测试工程师的使命就是让软件更加健壮、更加可靠、更加美好。我们就像是一群“特警”&#xff0c;在黑暗的代码中寻找漏洞和缺陷&am…

spring boot——自定义依赖实现自动配置

需求 要实现的功能是&#xff1a;实现一个可以支持miniooss两种方式&#xff0c;上传下载文件的自定义依赖。其中还包括一些创建桶、删除桶、删除文件等功能&#xff0c;但是最主要的是实现自动配置。 如果对spring理解很深的话&#xff0c;自动配置这些东西很容易理解&#…

php获取api接口数据的方法

API是应用程序的开发接口&#xff0c;在开发程序的时候&#xff0c;我们有些功能可能不需要从到到位去研发&#xff0c;我们可以拿现有的开发出来的功能模块来使用&#xff0c;而这个功能模块&#xff0c;就叫做库(libary)。比如说&#xff1a;要实现数据传输的安全&#xff0c…

传输层TCP与UDP协议

目录 传输层 传输层功能 传输层所提供的服务 传输层的两个协议 TCP协议与UDP协议 端口 端口分类 IP地址和端口的关系 UDP协议 前言&#xff1a; UDP报文格式 检验和的伪首部 伪首部内容 TCP协议 TCP报文格式 TCP协议数据段的理解 TCP的伪首部 伪首部内容 标…

基于Jeecgboot前后端分离的ERP系统开发系列--出库单(3)

继续对销售出库单进行完善与处理 一、列表显示状态 目前先给出库表单两种状态&#xff0c;未审核与审核通过状态&#xff0c;前端通过下面调整 { title:状态, align:"center", dataIndex: status, customRender:f…

Netty(四):优化与源码

文章目录1. 优化1.1 扩展序列化算法1.2 参数调优1&#xff09;CONNECT_TIMEOUT_MILLIS2&#xff09;SO_BACKLOG3&#xff09;ulimit -n4&#xff09;TCP_NODELAY5&#xff09;SO_SNDBUF & SO_RCVBUF6&#xff09;ALLOCATOR7&#xff09;RCVBUF_ALLOCATOR1.3 RPC 框架1&…

IDEA性能优化设置(解决卡顿问题)修改内存

在我们日常使用IDEA进行开发时&#xff0c;可能会遇到许多卡顿的瞬间&#xff0c;明明我们的机器配置也不低啊&#xff1f;为什么就会一直卡顿呢&#xff1f; 原来这是因为IDEA软件在我们安装的时候就设置了默认的内存使用上限&#xff08;通常很小&#xff09;&#xff0c;这就…

理解IM消息“可靠性”和“一致性”问题,以及解决方案探讨

试想如果一个IM连发出的消息都不知道对方到底能不能收到、发出的聊天内容对方看到的到底是不是“胡言乱语”&#xff08;严重乱序问题&#xff09;&#xff0c;这样的APP用户肯定不会让他在手机上过夜&#xff08;肯定第一时间卸载了&#xff09;&#xff0c;因为最基本的聊天逻…

python基础 | python基础语法

文章目录&#x1f4da;基础语法&#x1f407;输入和输出&#x1f955;print()输出&#x1f955;input()输入&#x1f407; 变量的命名&#x1f407;条件判断&#x1f955;单向判断&#x1f955;双向判断&#x1f955;多向判断&#x1f955;if嵌套&#x1f955;三元表达式&#…

漫画 | Python是一门烂语言?

这个电脑的主人是个程序员&#xff0c;他相继学习了C、Java、Python、Go&#xff0c; 但是似乎总是停留在Hello World的水平。 每天晚上&#xff0c;夜深人静的时候&#xff0c;这些Hello World程序都会热火朝天地聊天但是&#xff0c;这一天发生了可怕的事情随着各个Hello wor…

如何无报错运行代码YOLOv6,实现目标识别?

YOLOv6是由美团视觉团队开发的1.环境配置我们先把YOLOv6的代码clone下来git clone https://github.com/meituan/YOLOv6.git安装一些必要的包pip install pycocotools2.0作者要求pytorch的版本是1.8.0,我的环境是1.7.0&#xff0c;也是可以正常运行的pip install -r requirement…

RTOS之三裸机ADC转换与三轴加速计

参考&#xff1a;https://blog.csdn.net/qq_38427678/article/details/94607733各个pin口连接方式如下&#xff1a;// J1 J3 J4 J2// [ 1] [21] [40] [20]// [ 2] [22] [39] [19]// [ 3] [23] [38] [18]// [ 4] [24] [37] [17]// [ 5] [25] [36] [16]// [ 6] [26] [35] [15]// …

重温一下C#的时间类型,并简单写一个定时器功能

&#x1f389;&#x1f389; 时间是一个非常抽象的概念&#xff0c;本篇文章我们不深究目前电脑上的时候是如何保持全网同步。主要是讲讲在使用C#编程语言里的时间类型。最后使用定时任务简单写一个提醒功能&#xff0c;比如&#xff1a;每天10点准时打开一次csdn首页&#xff…