关于字符串解析的一点理解|关于字符串解析的一点理解 (以解析一段HTML字符串为例)

在分析一段字符串的时候,可以借助字符串的indexOf等方法,或者是正则表达式,可是,如果需要解析的是下面这段字符串:

文字

什么时候可能会需要解析类似这样的字符串?比如你可能希望的nodejs环境开发一个爬虫,分析爬到的页面内容,或者是像上面的设计,用html来表达希望绘制什么样的图形后通过js在canvas画布上绘制出用户的意图等。
下面,我们来一起看看,具体的怎么一步步分析处理上面的字符串包含的信息的。
我们把分析分为这几个步骤: 分析出符号 → 分析出单词 → 单词信息分析 → 获取整体信息
## 分析出符号
我们把一个最小的类似"语句"的称为单词(和编译原理中的单词加以区分),比如这里的一个标签,而为了得到单词,首先需要分析的称为符号。比如对 "你好"而言,就存在三个符号: ""、"你好"和""。
因此,符号就是容易分析出且在此基础上很容易分析出单词的存在,具体什么是符号,取决于分析的内容和目标。
上面的内容,分析出符号的最终结果就是:
关于字符串解析的一点理解|关于字符串解析的一点理解 (以解析一段HTML字符串为例)
文章图片

比如第二个符号,原始代码是"",经过分析得到,他是一个标签的开始部分,名称叫arc,有一些属性等。
那么,这样的符号是如何分析出来的?很简单,通过while循环即可。
在分析一个符号开始前,如果遇到的第一个非空白字符是"<",说明这是一个标签(可能是开始、结束或自闭合的),直到遇到">"的时候,分析结束,也就是获取了一个符号。
而如果在分析一个符号开始前,遇到的第一个非空白字符不是"<",说明这是一段文本,等遇到"<"的时候,回退一步即可获得一段文本符号。
而对于标签符号,只要在分析的时候额外加些判断,就可以获取更丰富的信息并获取属性值等。从而,就得到了上面的符号列表。
## 分析出单词
在上面符号列表的基础上,我们接下来将分析出下面的单词列表:
关于字符串解析的一点理解|关于字符串解析的一点理解 (以解析一段HTML字符串为例)
文章图片

很明显,单词明显比符号要少。那么,如何通过符号列表获取单词列表?这会比上一步容易的多。
首先,你读取了符号列表的第一个符号,如果是文本或者自闭合标签,就已经获取了第一个单词,否则,一定是开始标签。
现在,你把这个开始标签存放到栈(先进后出)中去,并占据单词列表的一个位置,接着观察下一个符号,如果是文本或者自闭合标签,就是一个新的单词,否则查看是否是开始标签,如果是,同样的处理,否则,判断是否和当前栈顶的元素匹配,如果匹配,出栈并完成了一个单词的匹配,不然就抛出错误。
如此反复下去,直到符号列表遍历完毕,观察此时的栈,如果还有元素,可以默认自闭合即可。
## 单词信息分析
在上一步,除了分析出单词外,还需要额外给每个单词标记层次(例如:根group是第一层,根的孩子是第二层,以此类推)。
层次是如何获取的?比如,你当前的层次是deep,如果遇到的下一个符号是开始符号,那么,下一个单词(或文本,下同)的层次就一个是deep+1,如果遇到的是结束符号,下一个单词就应该是deep-1,否则就依旧是deep。
获取整体信息 对于一个字符串表达式而言,就是求值,对于json字符串而言,就是获取json对象,而在此处,就是要获取一个带有关系的DOM树。
先看看最终的结果:
关于字符串解析的一点理解|关于字符串解析的一点理解 (以解析一段HTML字符串为例)
文章图片

我们拿节点""举例子。
通过parentNode和childNodes指明了它的父节点是第二个节点group,没有孩子,前一个兄弟preNode为null没有,后一个兄弟nextNode为4,也就是text标签。
同样的,我们来说说思路。
在单词列表中,拿出一个单词(其实也就是节点或文本节点),如果下一个单词的deep和当前的一样,就是兄弟关系,如果小一级,就是当前结点的孩子,这都比较容易。
如果比当前结点的deep大,怎么办?说明当前这个节点是叶子,需要回溯,回溯到deep和新的节点deep一样的即可,那么新的节点就是此节点的下一个兄弟,以此类推即可。
小结 【关于字符串解析的一点理解|关于字符串解析的一点理解 (以解析一段HTML字符串为例)】上述关于解析字符串html的算法,已经封装并对外开源: 解析xhtml为json对象

    推荐阅读