加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

lua 标签解析器

发布时间:2020-12-14 22:04:48 所属栏目:大数据 来源:网络整理
导读:lua 标签解析器 概述 一个类xml标签解析函数,将标签解析成Lua中的表结构 它可以用来解析简单xml结构,可以作为RichLabel控件的字符串解析组件(其实它现在就是这么用的;-)) 原理 使用lua的模式匹配,使用了模式串 %b%26lt;%26gt; %b 用来匹配对称的字符。常写

lua 标签解析器


概述


一个类xml标签解析函数,将标签解析成Lua中的表结构
它可以用来解析简单xml结构,可以作为RichLabel控件的字符串解析组件(其实它现在就是这么用的;-))

原理


使用lua的模式匹配,使用了模式串%b%26lt;%26gt;
%b用来匹配对称的字符。常写为%26nbsp;%bxy,x和y是任意两个不同的字符。 x作为匹配的开始,y作为匹配的结束。
比如,%b%26lt;%26gt;%26nbsp;匹配以%26nbsp;%26lt;%26nbsp;开始,以%26nbsp;%26gt;%26nbsp;结束的字符串

要解析的字符串

hello world
%26lt;div%26gt;hello world%26lt;/div%26gt;
你好
%26lt;div fontName='nihao' fontColor=#ffccdd%26gt;hello,world%26lt;/div%26gt;
%26lt;div%26gt;%26lt;/div%26gt;

代码基本结构

-- 迭代所有格式为%26lt;xxx%26gt;的标签(包含了标签头和标签尾)
local beginindex,endindex = string.find(text,"%b%26lt;%26gt;",1)
while beginindex do
    -- 获得下一个标签的位置
    beginindex,"%b%26lt;%26gt;",endindex)
end

上面获得的beginindex和endindex分别是标签的在字符串中开始和结束的index值 但并不区分标签头和标签尾,
还得判断标签到底是标签头还是标签尾。

-- 获得当前标签,字符串截取出来
local label = string.sub(text,beginindex,endindex)
-- 判断当前标签是不是以'%26lt;/'开头,若是以'%26lt;/'开头则代表为标签尾巴,否则为标签头
if string.find(label,"^%26lt;/") then
else
end

至此已经可以在正确的从字符串中提取所有的标签,并且区分出标签头和标签尾了

处理标签匹配问题
为了支持标签嵌套包含,我们得用一个栈记录标签头,要不然嵌套好几层标签不好判断内容被哪个标签修饰。
具体做法:
+ 若当前标签是标签头则将栈顶标签,到新标签头之间内容用栈顶标签修饰,并且将当前标签入栈
+ 若当前标签是标签尾则将栈顶标签,到新标签尾之间内容用栈顶标签修饰,并将栈顶标签出栈
简单来说:
栈顶标签修饰当前的内容(新标签和栈顶标签之间的内容) ,然后根据新标签是头还是尾决定入栈或出栈

我们没有考虑特殊情况,若字符串最完成不是标签那最外层处理会存在点问题。
好吧,那我们可以直接在字符串外层加上一组标签就好了,很简单吧。

现在我们解析出了内容和修饰内容的标签,离成功不远了!!

解析标签头
这应该是最简单的一部,但又是最繁琐的一步。
因为标签头内容很少了,格式也确定了,只要提取出标签名和属性的key-value对就可以了
不过提取属性key-value对比较繁琐,要考虑value的种种可能,当然我考虑的并不全面也没打算那么全面,只要功能够用就可以了

第一步
解析出标签名,简单的模式匹配

local labelnameindex1,labelnameindex2 = string.find(label,"%w+")

因为我们要解析的串大多是手写,为了减小书写难度,标签名属性名最好不区分大小写

-- 获得标签名称
local labelname = string.sub(label,labelnameindex1,labelnameindex2)
labelname = string.lower(labelname)

第二步
获取属性,还是模式匹配,匹配形式为 propertyname=propertyvalue(等号两边不能存在空格)
propertyname%26nbsp;要求就是字母或者数字的组合
propertyvalue%26nbsp;要求就比较多,因为颜色使用的是web的标记形式#FF33AA,而且字符串也可能是'括起来表示。
%w: 与任何字母/数字配对
%s: 与空白字符配对

-- value要求非空白字符并且不含有'%26gt;'字符的一个单词
string.gmatch(labelhead,"%w+%=[^%s%%26gt;]+")

gmatch会返回一个迭代器,每次运行都返回一个匹配串,所以我们这么写

for property in string.gmatch(labelhead,"%w+%=[^%s%%26gt;]+") do
end

在循环中我们可以处理每个属性对字符串无非就是根据=位置分离出属性名和属性值,属性名不需要处理,
把属性值做一下处理然后放到一个table中就好了,处理如下:

local equalmarkpos = string.find(property,"=")
-- 分离属性名和属性值
local propertyname = string.sub(property,1,equalmarkpos-1)
local propertyvalue = string.sub(property,equalmarkpos+1,string.len(property))
-- 属性名转为小写
propertyname = string.lower(propertyname)
-- 属性值处理
local continue = false
-- 1.检测是否为字符串(单引号或者双引号括起来)
local beginindex,endindex = string.find(propertyvalue,"['"].+['"]")
if beginindex then
    propertyvalue = string.sub(propertyvalue,beginindex+1,endindex-1)
    continue = true
end
-- 2.检测是否为布尔值
if not continue then
    local propertyvalue_lower = string.lower(propertyvalue)
    if propertyvalue_lower == BOOLEAN_TRUE then 
        propertyvalue = true 
        continue = true
    elseif propertyvalue_lower == BOOLEAN_FALSE then 
        propertyvalue = false 
        continue = true
    end
end
-- 3.检测是否为数字
if not continue then
    local propertyvalue_number = tonumber(propertyvalue)
    if propertyvalue_number then 
        propertyvalue = propertyvalue_number 
        continue = true
    end
end
-- 若以上都不是,则默认直接为字符串
labelparams[propertyname] = propertyvalue

顺便吐槽一下lua没有关键字continue,造成程序嵌套层次变深

最后完整代码在我的github上面叫labelparser,lua5.1解析器可以直接运行,无需任何依赖

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读