在Lua中使用LPeg分析多行数据
我有一些包含多行块的文本文件,如下:
2011/01/01 13:13:13,<AB>, Some Certain Text,=,
[
certain text
[
0: 0 0 0 0 0 0 0 0
8: 0 0 0 0 0 0 0 0
16: 0 0 0 9 343 3938 9433 8756
24: 6270 4472 3182 2503 1768 1140 836 496
32: 326 273 349 269 144 121 94 82
40: 64 80 66 59 56 47 50 46
48: 64 35 42 53 42 40 41 34
56: 35 41 39 39 47 30 30 39
Total count: 12345
]
certain text
]
some text
2011/01/01 14:14:14,<AB>, Some Certain Text,=,
[
certain text
[
0: 0 0 0 0 0 0 0 0
8: 0 0 0 0 0 0 0 0
16: 0 0 0 4 212 3079 8890 8941
24: 6177 4359 3625 2420 1639 974 594 438
32: 323 286 318 296 206 132 96 85
40: 65 73 62 53 47 55 49 52
48: 29 44 44 41 43 36 50 36
56: 40 30 29 40 35 30 25 31
64: 47 31 25 29 24 30 35 31
72: 28 31 17 37 35 30 20 33
80: 28 20 37 25 21 23 25 36
88: 27 35 22 23 15 24 34 28
Total count: 123456
]
certain text
some text
]
这些可变长度块存在于文本之间。我想读取所有":"后面的数字,并将它们保留在各自的数组中。 在这种情况下,将有两个数组:
array1 = { 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 343 3938 9433 8756 6270 4472 3182 2503 1768 1140 836 496 326 273 349 269 144 121 94 82 64 80 66 59 56 47 50 46 64 35 42 53 42 40 41 34 35 41 39 39 47 30 30 39 12345 }
array2 = { 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 212 3079 8890 8941 6177 4359 3625 2420 1639 974 594 438 323 286 318 296 206 132 96 85 65 73 62 53 47 55 49 52 29 44 44 41 43 36 50 36 40 30 29 40 35 30 25 31 47 31 25 29 24 30 35 31 28 31 17 37 35 30 20 33 28 20 37 25 21 23 25 36 27 35 22 23 15 24 34 28 123456 }
我发现 lpeg 可能是实现它的一种轻量级方法。但我对 PEG 和 LPeg 完全不了解。求助!
尝试使用此代码,它不使用 LPEG:
-- 假设 T 包含文本
local a={}
local i=0
for b in T:gmatch("%b[]") do
b=b:gsub("%d+:","")
i=i+1
local t={}
local j=0
for n in b:gmatch("%d+") do
j=j+1; t[j]=tonumber(n)
end
a[i]=t
end
LPEG 版本:
local lpeg = require "lpeg"
local lpegmatch = lpeg.match
local C, Ct, P, R, S = lpeg.C, lpeg.Ct, lpeg.P, lpeg.R, lpeg.S
local Cg = lpeg.Cg
local data_to_arrays
do
local colon = P":"
local lbrak = P"["
local rbrak = P"]"
local digits = R"09"^1
local eol = P"\n\r" + P"\r\n" + P"\n" + P"\r"
local ws = S" \t\v"
local optws = ws^0
local getnum = C(digits) / tonumber * optws
local start = lbrak * optws * eol
local stop = optws * rbrak
local line = optws * digits * colon * optws
* getnum * getnum * getnum * getnum
* getnum * getnum * getnum * getnum
* eol
local count = optws * P"Total count:" * optws * getnum * eol
local inner = Ct(line^1 * count^-1)
--local inner = Ct(line^1 * Cg(count, "count")^-1)
local array = start * inner * stop
local extract = Ct((array + 1)^0)
data_to_arrays = function (data)
return lpegmatch (extract, data)
end
end
实际上,这只适用于数据块中每行恰好有八个整数的情况。
根据输入的形式,这可能是个诅咒,也可能是个祝福 ;-)
以下是测试文件:
data = [[
some text
[
some text
[
0: 0 0 0 0 0 0 0 0
8: 0 0 0 0 0 0 0 0
16: 0 0 0 9 343 3938 9433 8756
24: 6270 4472 3182 2503 1768 1140 836 496
32: 326 273 349 269 144 121 94 82
40: 64 80 66 59 56 47 50 46
48: 64 35 42 53 42 40 41 34
56: 35 41 39 39 47 30 30 39
Total count: 12345
]
some text
]
some text
[
some text
[
0: 0 0 0 0 0 0 0 0
8: 0 0 0 0 0 0 0 0
16: 0 0 0 4 212 3079 8890 8941
24: 6177 4359 3625 2420 1639 974 594 438
32: 323 286 318 296 206 132 96 85
40: 65 73 62 53 47 55 49 52
48: 29 44 44 41 43 36 50 36
56: 40 30 29 40 35 30 25 31
64: 47 31 25 29 24 30 35 31
72: 28 31 17 37 35 30 20 33
80: 28 20 37 25 21 23 25 36
88: 27 35 22 23 15 24 34 28
]
some text
some text
]
]]
local arrays = data_to_arrays (data)
for n = 1, #arrays do
local ar = arrays[n]
local size = #ar
io.write (string.format ("[%d] = { --[[size: %d items]]\n ", n, size))
for i = 1, size do
io.write (string.format ("%d,%s", ar[i], (i % 5 == 0) and "\n " or " "))
end
if ar.count ~= nil then
io.write (string.format ("\n [\"count\"] = %d,", ar.count))
end
io.write (string.format ("\n}\n"))
end
phg已经为您的问题提供了一个漂亮的LPeg解决方案,但这里是另一个使用LPeg的re模块的解决方案。语法更接近BNF,并且使用的运算符更像是“正则表达式”,因此这个解决方案可能更容易理解。
re = require 're'
function dump(t)
io.write '{'
for _, v in ipairs(t) do
io.write(v, ',')
end
io.write '}\n'
end
local textformat = [[
data_in <- block+
block <- text '[' block_content ']'
block_content <- {| data_arr |} / (block / text)*
data_arr <- (text ':' nums whitesp)+
text <- whitesp [%w' ']+ whitesp
nums <- (' '+ {digits} -> tonumber)+
digits <- %d+
whitesp <- %s*
]]
local parser = re.compile(textformat, {tonumber = tonumber})
local arr1, arr2 = parser:match(data)
dump(arr1)
dump(arr2)
每个数据数组块都被捕获到一个单独的表中,并作为match的输出之一返回。
使用与上面相同的输入data,会匹配和捕获两个块,因此返回2个表。检查这两个表会得到:
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,343,3938,9433,8756,6270,4472,3182,2503, 1768,1140,836,496,326,273,349,269,144,121,94,82,64,80,66,59,56,47,50,46,64,35,42 ,53,42,40,41,34,35,41,39,39,47,30,30,39,12345,} {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,212,3079,8890,8941,6177,4359,3625,2420, 1639,974,594,438,323,286,318,296,206,132,96,85,65,73,62,53,47,55,49,52,29,44,44, 41,43,36,50,36,40,30,29,40,35,30,25,31,47,31,25,29,24,30,35,31,28,31,17,37,35,30 ,20,33,28,20,37,25,21,23,25,36,27,35,22,23,15,24,34,28,}
我知道这是一个晚回复,但是通过定义更少的语法,以下模式查找开头的[并捕获到每个未被:后缀的数字,直到遇到关闭的]。然后重复整个block,直到没有匹配项。
local patt = re.compile([=[
data <- {| block |}+
block <- ('[' ((%d+ ':') / { %d+ } -> int / [^]%d]+)+ ']') / ([^[]+ block)
]=], { int = tonumber })
你可以用类似这样的方式在一个表中捕获所有恢复的数组
local a = { patt:match[=[ ... ]=] }
- 如何将两个不同的lua文件合成一个 东西有点长 大佬请耐心看完 我是小白研究几天了都没搞定
- 如何在roblox studio中1:1导入真实世界的地形?
- 求解,lua_resume的第二次调用继续执行协程问题。
- 【上海普陀区】内向猫网络招募【Skynet游戏框架Lua后端程序员】
- SF爱好求教:如何用lua实现游戏内调用数据库函数实现账号密码注册?
- Lua实现网站后台开发
- LUA错误显式返回,社区常见的规约是怎么样的
- lua5.3下载库失败
- 请问如何实现文本框内容和某个网页搜索框内容连接,并把网页输出来的结果反馈到另外一个文本框上
- lua lanes多线程使用
- 一个kv数据库
- openresty 有没有比较轻量的 docker 镜像
- 想问一下,有大佬用过luacurl吗
- 在Lua执行过程中使用Load函数出现问题
- 为什么 neovim 里没有显示一些特殊字符?
- Lua比较两个表的值(不考虑键的顺序)
- 有个lua简单的项目,外包,有意者加微信 liuheng600456详谈,最好在成都
- 如何在 Visual Studio 2022 中运行 Lua 代码?
- addEventListener 返回 nil Lua
- Lua中获取用户配置主目录的跨平台方法
我的纯 Lua 字符串库解决方案是这样的:
local bracket_pattern = "%b[]" --获取括号内的模式 local number_pattern = "(%d+)%s+" --解析数字的模式 local output_array = {} --输出二维数组 local i = 1 local j = 1 local tmp_number local tmp_sub_str -- 遍历 [string] for tmp_sub_str in file_content:gmatch(bracket_pattern) do table.insert(output_array, i, {}) --添加新的 [string] 组 -- 循环遍历 numberWHITESPACE for tmp_number in tmp_sub_str:gmatch(number_pattern) do -- 添加 [string] 组元素(数字) table.insert(output_array[i], tonumber(tmp_number)) end i = i + 1 endEDIT: 这也适用于更新后的文件格式。