首页 文章

当在Lua中使用带括号的模式匹配时,如何使用“%2”来获取捕获组

提问于
浏览
0

我试图解析一个文本文件,并使用lua将其转换为表(或JSON) . 示例测试文件如下:

ipv4     2 tcp      6 3598 ESTABLISHED src=192.168.1.117 dst=137.194.2.78 sport=59078 dport=80 packets=4 bytes=298 src=137.194.2.78 dst=132.227.127.212 sport=80 dport=59078 packets=3 bytes=567 [ASSURED] mark=0 use=2
ipv4     2 udp      17 55 src=192.168.1.117 dst=157.56.149.60 sport=49991 dport=3544 packets=5 bytes=445 [UNREPLIED] src=157.56.149.60 dst=132.227.127.212 sport=3544 dport=49991 packets=0 bytes=0 mark=0 use=2
ipv4     2 tcp      6 3420 ESTABLISHED src=192.168.1.104 dst=193.51.224.187 sport=35918 dport=443 packets=19 bytes=2521 src=193.51.224.187 dst=132.227.127.212 sport=443 dport=35918 packets=16 bytes=9895 [ASSURED] mark=0 use=2
ipv4     2 udp      17 59 src=192.168.1.117 dst=192.168.1.255 sport=17500 dport=17500 packets=139 bytes=23908 [UNREPLIED] src=192.168.1.255 dst=192.168.1.117 sport=17500 dport=17500 packets=0 bytes=0 mark=0 use=2
...

请注意,每行中的数据可以根据方向(前向和反向路径流)分为两部分 . 如果你有一个linux系统/ openwrt路由器,你可以使用 conntrack 命令或阅读 /proc/net/nf_conntrack 获得类似的测试文件 .

我想要检索的是以下信息:

{ 1:
    {
    "bytes":    298,
    "src":      "192.168.1.117",
    "sport":    59078,
    "layer4":   "tcp",
    "dst":      "137.194.2.78",
    "dport":    80,
    "layer3":   "ipv4",
    "packets":  4,
    "rbytes":   567,
    "rpackets": 3
    },
{ 2: ...

其中rbytes,rpackets用于反向的字节和数据包(我的示例文本文件中第1行的后半部分) .

我的解析器如下:*

function conntrack(callback)
local connt = {}
if io.open("conntrack.temp", "r") then

    for line in io.lines("conntrack.temp") do
            line = line:match("^(.-( [^ =]+=).-)%2")
        local entry, flags = _parse_mixed_record(line, " +")

            if flags[6] ~= "TIME_WAIT" then
                entry.layer3 = flags[1]
                entry.layer4 = flags[3]
                for i=1, #entry do
                    entry[i] = nil
                end
                if callback then
                    callback(entry)
                else
                    connt[#connt+1] = entry
                end
            end
    end   
else
    return nil
end
return connt
end

function _parse_mixed_record(cnt, delimiter)
delimiter = delimiter or "  "
local data = {}
local flags = {}

for i, l in pairs(cnt:split("\n")) do
    for j, f in pairs(l:split(delimiter)) do
        local k, x, v = f:match('([^%s][^:=]*) *([:=]*) *"*([^\n"]*)"*')
        if k then
            if x == "" then
                table.insert(flags, k)
            else
                data[k] = v
            end
        end
    end
end

return data, flags
end

调用上面的函数(在代码中包含一个简单的 split 方法之后),我可以解析文件 only upto the first half of each line . 基本上,没有解析 rbytesrpackets . 我知道负责这个的代码是

line = line:match(“^(.-([^=] =).-)%2”)

代码中此行后面的 print(line) 语句向我显示:

ipv4 2 tcp 6 3598 ESTABLISHED src = 192.168.1.117 dst = 137.194.2.78 sport = 59078 dport = 80 packets = 4 bytes = 298

所以,语句使用一个令人困惑的模式匹配来分割文件的每一行,我稍后会对它进行一些理解 . 我仍然没有得到的部分是捕获模式后发生的 %2 . 我知道它用于以某种方式访问捕获的模式,但我应该如何更改此语句,以便 line 包含正向路径字节和数据包计数,以及反向路径?我的主要问题是: what exactly is the pattern in this statement? 我可能会删除这一行来解析整个语句,但我想理解为什么原始编码器会这样做 .

我've been through the lua pattern matching manual but I'仍然对使用 %<some_number> 捕获输出感到困惑 . 为什么不 %1%3 工作?

我找到了两个相关的stackoverflow问题:Q1Q2 . 将会有更深入的解释 .

此外,目前我无法使用此处提供的代码恢复超时值(line1 3598 中的第5个字)或连接状态( ESTABLISHED[ASSURED] ) . 我仍然是lua的初学者,并希望尽快解决这个问题 .

*注意:此解析器是我在openwrt路由器上的luci sys模块中提供的解析器的固定版本 . 有关详细信息,请参见original luci.sys sourcecode .

在使用态度调整12.09时,我注意到他们的net.conntrack()由于无法将对象解析为正确的JSON格式而无法正常工作 . 使用此模式的相关函数在sys.lua文件中给出,称为函数conntrack(回调)和内部函数_parse_mixed_record(cnt,delimiter) . 我的路由器使用luci-0.11和lua 5.1.4 .

1 回答

  • 0

    该模式旨在仅保留每条线的前部 . 这是它如何做到的 . 第二个括号 ( [^ =]+=) 捕获 " stuff=" 形式的第一个子字符串 . 然后,如果再次出现相同的字符串 " stuff=" ,则模式结尾处的 %2 将仅匹配 . 所以在一条线上

    ipv4     2 tcp      6 3598 ESTABLISHED src=192.168.1.117 dst=137.194.2.78 sport=59078 dport=80 packets=4 bytes=298 src=137.194.2.78 dst=132.227.127.212 sport=80 dport=59078 packets=3 bytes=567 [ASSURED] mark=0 use=2
    

    第二次捕获将是 " src=" ,所以第一次捕获,即分配给 line 的捕获,将是该行的整个初始部分,直到第二次 src= 出现之前,即这个初始部分:

    ipv4     2 tcp      6 3598 ESTABLISHED src=192.168.1.117 dst=137.194.2.78 sport=59078 dport=80 packets=4 bytes=298
    

    如果你想获得后半部分,并将其分配给另一个变量,你可以用 line = ... 语句替换

    line1, _, line2 = line:match("^(.-( [^ =]+=).-)(%2.*)$")
    

    这将为line1分配线的前半部分(如先前分配给line),并将line2分配给line2,其余部分从 " src=" 的第二次出现开始 . 对于上面的示例行,你会得到

    line1 = "ipv4     2 tcp      6 3598 ESTABLISHED src=192.168.1.117 dst=137.194.2.78 sport=59078 dport=80 packets=4 bytes=298"
    line2 = " src=137.194.2.78 dst=132.227.127.212 sport=80 dport=59078 packets=3 bytes=567 [ASSURED] mark=0 use=2"
    

    注意: line1line2 之间的 _ 用于捕获第二次捕获(这里是字符串 " src=" ),请记住该匹配按顺序返回所有捕获,无论您是否需要它们 .

相关问题