1. 如何将一个字符传转换成一个AST树结构。

直接上代码:

 

const attribute = /^\s*([^\s"'<>\/=]+)(?:\s*(=)\s*(?:"([^"]*)"+|'([^']*)'+|([^\s"'=<>`]+)))?/
const ncname = `[a-zA-Z_][\\-\\.0-9_a-zA-Z]*`
const qnameCapture = `((?:${ncname}\\:)?${ncname})`
// 匹配 <div
const startTagOpen = new RegExp(`^<${qnameCapture}`)
// 匹配 > />
const startTagClose = /^\s*(\/?)>/
// 匹配 </div>
const endTag = new RegExp(`^<\\/${qnameCapture}[^>]*>`)
const doctype = /^<!DOCTYPE [^>]+>/i //注意树形的html 只能有一个根节点
function parseHtmlToAst(html){ let text,root,currentParent,stack=[]; while(html){
let textEnd=html.indexOf("<");
if(textEnd===0){
//查找开始tag
const startTagMatch=parseStartTag();
if(startTagMatch){
//生成AST树
start(startTagMatch.tagName,startTagMatch.attrs);
continue;
}
//查找结束标签
const endTagMatch=html.match(endTag);
if(endTagMatch){
advance(endTagMatch[0].length);
//构造ast树
end(endTagMatch[1]);
continue;
} }
//文本节点
if(textEnd>0){
text=html.substring(0,textEnd);
}
if(text){
//截取字符串
advance(text.length);
chars(text);
} }
//截些开始标记
function parseStartTag(){
const start=html.match(startTagOpen); let end,attr;
//找到开始标记
if(start){
const match={
tagName:start[1],
attrs:[]
} advance(start[0].length)
//配置属性
while(!(end=html.match(startTagClose)) && (attr=html.match(attribute))){ match.attrs.push({
name:attr[1],
value: attr[3] || attr[4] || attr[5]
})
advance(attr[0].length); }
//匹配结束字符 > 或 />
if(end){
advance(end[0].length);
return match;
}
} } //截取字符串
function advance (n) {
html = html.substring(n)
}
//构造AST树形
function start(tagName,attrs){
const element=createAstElement(tagName,attrs); if(!root){
root=element;
}
currentParent=element;
stack.push(element);
} //结束钩爪树形
function end(tagName){
const element=stack.pop();
currentParent=stack[stack.length-1];
if(currentParent){
element.parent=currentParent;
currentParent.children.push(element);
} }
//处理文本节点
function chars(text){
text=text.trim();
if(text.length>0){
currentParent.children.push({
type:3,
text
})
} } function createAstElement(tagName,attrs){
return {
tag: tagName,
type: 1,
children:[],
attrs,
parent }
}
return root; } let html=`<div id="app" style="color:red;width:200px">
你好:{{name}}
<span class="text" style="color:green">{{age}}
</span>
</div>
`; let root=parseHtmlToAst(html);
console.info(root)

代码的逻辑是:

对字符串的处理,从头开始处理,先找 < 开头的字符,如果找到则用 正则表达式查找 <div 的标签,找到后,截取 后面的字符串,然后循环查找 属性,直到 找到 > 或 />字符为止,找到让后截取后面的字符串。

中间用到了堆栈作为树节点作为串联。

2.构造结果

解析HTML字符串成AST树的更多相关文章

  1. js字符串解析与转换成数字

    解析允许字符串中含有非法数字字符,解析按从左至右的顺序,如果遇到非数字字符就停止.而转换不允许出现非数字字符,否则会失败并返回NaN

  2. dom4j解析xml字符串实例

    DOM4J 与利用DOM.SAX.JAXP机制来解析xml相比,DOM4J 表现更优秀,具有性能优异.功能强大和极端易用使用的特点,只要懂得DOM基本概念,就可以通过dom4j的api文档来解析xml ...

  3. C#解析JSON字符串总结

    JSON文件读取到内存中就是字符串,.NET操作JSON就是生成与解析JSON字符串. 操作JSON通常有以下几种方式: 1. 原始方式:按照JSON字符串自己来解析. 2. 通用方式[★★★★★]: ...

  4. Json转model对象,model转json,解析json字符串

    GitHub链接: https://github.com/mozhenhau/D3Json D3Json 通过swift的反射特性,把json数据转换为model对象,本类最主要是解决了其他一般jso ...

  5. C#解析JSON字符串总结(转载)

    JSON文件读取到内存中就是字符串,.NET操作JSON就是生成与解析JSON字符串. 操作JSON通常有以下几种方式: 1. 原始方式:按照JSON字符串自己来解析. 2. 通用方式[★★★★★]: ...

  6. java解析Json字符串之懒人大法

    面对Java解析Json字符串的需求,有很多开源工具供我们选择,如google的Gson.阿里巴巴的fastJson.在网上能找到大量的文章讲解这些工具的使用方法.我也是参考这些文章封装了自己的Jso ...

  7. 一、JSON解析与字符串化

    JSON.stringify() 序列化对象.数组或原始值 语法:JSON.stringify(o,filter,indent) o,要转换成JSON的对象.数组或原始值 filter,指定要序列化的 ...

  8. Atitit.注解and属性解析(2)---------语法分析 生成AST attilax总结 java .net

    Atitit.注解and属性解析(2)---------语法分析 生成AST  attilax总结  java .net 1. 应用场景:::因为要使用ui化的注解 1 2. 使用解释器方式来实现生成 ...

  9. JackSon解析json字符串

    JackSon解析json字符串 原文:http://blog.csdn.net/java_huashan/article/details/9353903 概述 jackson解析json例子 准备工 ...

  10. java解析xml字符串(用dom4j)

    package com.smsServer.Dhst; import java.util.HashMap; import java.util.Iterator; import java.util.Ma ...

随机推荐

  1. 【倒计时3天】“CSIG企业行”走进合合信息,大咖解密智能文档处理背后的底层技术及AI未来展望

    3月18日,由中国图象图形学会(CSIG)主办,合合信息.CSIG文档图像分析与识别专业委员会联合承办的"CSIG企业行"系列活动将正式举办,通过搭建学术界与企业交流合作平台,为企 ...

  2. BOOST 环形队列circular_buffer

    BOOST库的环形队列比较灵活,前插或后插,删除队首或删除队尾元素,都支持. 只贴代码: #include <boost/circular_buffer.hpp> #include < ...

  3. for循环遍历的盗版笔记

    遍历一个List有如下几种方法   5 6 是 java8 增强for循环底层由Iterator实现 增强for的出现时替代迭代器的,所以在遍历集合或者遍历数组就可以使用增强for去完成 增强for循 ...

  4. 《你必须掌握的Entity Framework 6.x与Core 2.0》代码下载

      https://item.jd.com/12376014.html<你必须掌握的Entity Framework 6.x与Core 2.0>代码下载,共享代码: https://git ...

  5. Linux内核中cpu_capacity是什么?

    cpu_capacity 在Linux内核中,cpu_capacity 是用于表示每个CPU的处理能力的一个参数,通常用于调度器的负载均衡.它表明不同的CPU核心在计算资源分配中的相对性能,尤其在异构 ...

  6. 4.3.2 等比数列的前n项和公式

    \({\color{Red}{欢迎到学科网下载资料学习 }}\) [ [基础过关系列]高二数学同步精品讲义与分层练习(人教A版2019)] ( https://www.zxxk.com/docpack ...

  7. C++第六节课 引用变量 指针的升级版

    #include <iostream> using namespace std; // C++的引用 是C指针的升级 可以提高代码的稳定性和健壮性 // const 修饰的引用 是 常引用 ...

  8. ORM的设计思想

    1 以面向对象的思想来完成对于数据库的操作! 2 万物皆对象

  9. 最详细CentOS7.6安装openGauss5.0.3教程

    一.环境准备 1.1 主机信息 项目 内容 操作系统 CentOS7.6 IP 192.168.4.201 主机名 opgs201 CPU 8core 内存 16GB 磁盘1 100GB 1.2 操作 ...

  10. 强大的无头UI表格库:TanStack Table!Github Star达到了惊人的25K!

    强大的无头UI表格库:TanStack Table!Github Star达到了惊人的25K! 在构建现代化 Web 应用时,表格和数据网格是常见的 UI 组件,特别是在处理大量数据或需要复杂交互时, ...