加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

lua 正则实现指定次数匹配

(2017-08-18 14:51:38)
分类: lua
      最近在写lua,需要验证参数合法性,比如参数格式为多个值用逗号分割,但是值的数量不固定。发现其原生正则无法实现php正则中类似/^(\d+,){0,4}\d+$/这样的匹配验证,网上搜索也无果,所以自己用lua实现了,写的不好还请多多指教。

-- 正则匹配-可指定匹配次数(类似于php正则中的{x,y})
-- @param stirng 要匹配的字符串
-- @regex string 匹配正则
-- @return nil or string 如果匹配到则返回匹配到的字符串 否则 返回nil
-- @desc 支持不含{} 和 仅含1次{}的正则匹配
-- @desc 如果正则参数不包含{} 则按照普通正则处理
-- @desc 如果正则参数包含{} 支持格式 {n,} 匹配n次及以上 {,m} 匹配m次及以下 {n,m} 匹配n至m次 {n} 匹配n次
local function n_gmatch(str,regex)
    local rs
    local match_str_all = '' -- 累计匹配到的字符串
    if type(str) == 'string' and str ~= '' and type(regex) == 'string' and regex ~= '' then
        local _start,_end,reg_pre,min_num,comma,max_num,reg_end = string.find(regex, '^([^%{%}]+)%{(%d*)(,?)(%d*)%}([^%{%}]*)$')
        if _start and _end then
            -- 正则包含{}
            if min_num == '' and max_num == '' then
                -- {}内容为空
                -- print('{}内容为空')
            else
                if comma == '' then
                    -- {n} 格式
                    max_num = min_num
                end
                min_num = tonumber(min_num) or 0
                max_num = tonumber(max_num) or 99999999

                if min_num <= max_num then

                    -- print('前置正则:'..reg_pre,'后置正则:'..reg_end,'最小次数:'..min_num,'最大次数:'..max_num)

                    local start_est,end_est = false,false --是否是从最开始或最结尾匹配
                    if string.sub(reg_pre,1,1) == '^' then
                        start_est = true
                        reg_pre = string.sub(reg_pre,2)
                    end

                    local match_num = 0
                    for match in string.gmatch(str, reg_pre) do
                        match_num = match_num + 1
                        match_str_all = match_str_all..match
                        -- print('match_str_all:'..match_str_all)
                        -- 判断是否是连续匹配
                        local _start,_end = string.find(str,match_str_all,1,false)
                        if not _start or not _end then
                            -- print('非连续匹配')
                            match_num = 0
                            break
                        elseif match_num == 1 and start_est then
                            -- 正则中包含^ 判断第一次匹配到的字符串是否在str的开头
                            if _start ~= 1 then
                                -- print('第1次匹配内容:'..match..'不在str开头,结束匹配')
                                match_num = 0
                                break
                            end
                        end

                        if max_num and match_num >= max_num then
                            -- print('匹配次数到达上限'..max_num..',结束{...}前字符匹配')
                            break
                        end
                    end

                    if match_num < min_num then
                        -- print('匹配次数小于最小匹配次数'..min_num)
                    else
                        local str_remain = ''
                        if match_str_all == '' then
                            str_remain = str
                        else
                            local _start,_end = string.find(str,match_str_all,1,false)
                            str_remain = string.sub(str,_end+1)
                        end

                        -- print('str已匹配:'..match_str_all,'str剩余:'..str_remain,'reg剩余:'..reg_end)

                        if reg_end == '' then
                            rs = match_str_all
                        else
                            -- 拿剩余字符和{}后面的正则匹配
                            local _start,_end =string.find(str_remain,'^'..reg_end)
                            if _start and _end then
                                local str_match = string.sub(str_remain,_start,_end)
                                match_str_all = match_str_all..str_match
                                rs = match_str_all
                            end
                        end
                    end
                else
                    -- print('最大值小于最小值')
                end
            end
        else
            -- 沿用普通正则 find
            -- print('正则不符合...{}...格式,沿用普通正则匹配')
            local _start,_end = string.find(str,regex)
            if _start and _end then
                match_str_all = string.sub(str,_start,_end)
                rs = match_str_all
            end
        end
    else
        -- str或regex格式不正确
        -- print('str或regex格式不正确')
    end
    return rs
end

local str = "aaaaa123,456,10,5"
print(n_gmatch(str,'^(%d+,){1,3}%w+$')) -- nil
print(n_gmatch(str,'(%d+,){1,3}%w+$')) -- 123,456,10,5
print(n_gmatch(str,'%d+,')) -- 123,

0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有