在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
概述一个类xml标签解析函数,将标签解析成Lua中的表结构 原理 使用lua的模式匹配, 使用了模式串 要解析的字符串 hello world <div>hello world</div> 你好 <div fontName='nihao' fontColor=#ffccdd>hello,world</div> <div></div> 代码基本结构 -- 迭代所有格式为<xxx>的标签(包含了标签头和标签尾巴) local index = 0 for beginindex, endindex in function() return string.find(text, "%b<>", index) end do local label = string.sub(text, beginindex, endindex) index = endindex + 1 end 上面获得的beginindex和endindex分别是标签的在字符串中开始和结束的index值 但并不区分标签头和标签尾, -- 获得当前标签,字符串截取出来 local label = string.sub(text, beginindex, endindex) -- 判断当前标签是不是以'</'开头,若是以'</'开头则代表为标签尾巴,否则为标签头 if string.find(label, "^</") then else end 至此已经可以在正确的从字符串中提取所有的标签,并且区分出标签头和标签尾了 处理标签匹配问题 我们没有考虑特殊情况,若字符串最完成不是标签那最外层处理会存在点问题。 -- 检测开头和结尾是否为标签 <xxx>即为标签 if not string.find(text, "^%b<>.+%b<>$") then -- 在最外层包装一个标签,便于解析时的统一处理,不用处理没有包装标签的情况 text = table.concat({LABEL_DIV_BEGIN, text, LABEL_DIV_END}) end
现在我们解析出了内容和修饰内容的标签,离成功不远了!! 解析标签头 第一步 local labelnameindex1, labelnameindex2 = string.find(label, "%w+") 因为我们要解析的串大多是手写,为了减小书写难度,标签名属性名最好不区分大小写 -- 获得标签名称 local labelname = string.sub(label, labelnameindex1, labelnameindex2) labelname = string.lower(labelname) 第二步 -- value要求非空白字符并且不含有'>'字符的一个单词 string.gmatch(labelhead, "%w+%=[^%s%>]+") gmatch会返回一个迭代器,每次运行都返回一个匹配串,所以我们这么写 for property in string.gmatch(labelhead, "%w+%=[^%s%>]+") do end 在循环中我们可以处理每个属性对字符串无非就是根据 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 顺便吐槽一下 最后完整代码在我的github上面叫labelparser,lua5.1解析器可以直接运行,无需任何依赖 ------------------------------------------------------------------------------------------------ 14-11-20:更新v1.0.1
今天晚上突然兴起决定添加上自闭合的支持,其实也很简单,首先主循环发生了改变: local beginindex, endindex = string.find(text, "%b<>", 1) while beginindex do -- 获得当前标签 local label = string.sub(text, beginindex, endindex) -- 检测字符串是否以"</"开头 if string.find(label, "^</") then -- 标签尾 _M.disposeLabelTail(labelheadstack, parsedtable, text, label, beginindex, endindex) elseif string.find(label, "/>$") then -- 检测以'/>'结尾 -- 自闭合标签 _M.disposeLabelSelfClosing(labelheadstack, parsedtable, text, label, beginindex, endindex) else-- 检测到标签头 _M.disposeLabelHead(labelheadstack, parsedtable, text, label, beginindex, endindex) end -- 获得下一个标签的位置 beginindex, endindex = string.find(text, "%b<>", endindex) end 主循环这里添加了一个自闭合标签的判断,然后相关的标签处理都提取出去了,主要有两点原因:
参数着实不少,不过逻辑清晰了很多,主循环结构一目了然(本来也没多少行代码;-)) 自闭合标签为什么加在中间呢? 自闭合标签的条件,不能以'</'开头,并且要以'/>'结尾,所以加在中间比较好判断这个条件 下面看看自闭合标签的处理,更加简单 -- 处理自闭合标签 function _M.disposeLabelSelfClosing(labelheadstack, parsedtable, text, label, beginindex, endindex) _M.disposeLabelHead(labelheadstack, parsedtable, text, label, beginindex, endindex) _M.disposeLabelTail(labelheadstack, parsedtable, text, label, beginindex, endindex, true) end 直接调用处理标签头和标签尾的函数,就可以了 因为处理自闭合标签和处理一对儿有些相似之处,可以直接使用处理一对儿标签方法直接处理自闭合标签 (虽然这样处理自闭合标签过程有些冗余,但是无需专门的代码处理自闭合标签) 首先,碰到自闭合标签之后,要将自闭合标签之前内容使用栈顶标签头修饰 然后标签头可以入栈,然后又直接是标签头出栈,修饰栈顶标签到当前标签直接内容,由于两个标签是同一个标签, 它们之间内容为空,直接处理这个标签属性即可 这样其实就差不多了,具体代码还是参照github
|
请发表评论