我正在尝试使用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
方法之后),我可以解析文件,直到每行的前半部分。基本上,没有解析rbytes
或rpackets
。我知道负责这个的代码是
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
包含前向路径字节和数据包计数,以及反向路径?
我的主要问题是:这个语句中的模式究竟是什么?我可能会删除这一行来解析整个语句,但我想理解为什么原始编码器会这样做。< / p>
我一直在浏览lua模式匹配手册,但我仍然对使用%<some_number>
捕获输出感到困惑。为什么%1
或%3
无效?
我找到了两个相关的stackoverflow问题:Q1,Q2。将会有更深入的解释。
此外,目前我无法使用此处提供的代码恢复超时值(第1行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。
答案 0 :(得分:0)
该模式旨在仅保留每条线的前部。这是它如何做到的。第二个括号( [^ =]+=)
捕获表单" stuff="
的第一个子字符串。然后,只有在相同的字符串%2
再次出现时,模式末尾的" stuff="
才会匹配。所以在像
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
如果你想获得后半部分,并将其分配给另一个变量,你可以用{/ p>替换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"
注意:_
和line1
之间的line2
可以捕获第二次捕获(这里是字符串" src="
),请记住该匹配返回所有捕获按顺序,无论你是否想要它们。