解析Lua字符串,更具体地说是换行
问题描述:
我试图解析Lua 5.3字符串。但是,我遇到了一个问题。例如,解析Lua字符串,更具体地说是换行
$ lua
Lua 5.3.4 Copyright (C) 1994-2017 Lua.org, PUC-Rio
> print(load('return "\\z \n\r \n\r \r\n \n \n \\x"', "@test"))
nil test:6: hexadecimal digit expected near '"\x"'
>
> print(load('return "\\z\n\r\n\r\r\n\n\n\\x"', "@test"))
nil test:6: hexadecimal digit expected near '"\x"'
这两个错误在第6行,以及背后的逻辑很简单:吃换行符(\ r或\ n)的,如果他们从目前的一个不同的(我相信这准确描述lua词法分析器是如何工作的,但我可能是错的)。
我有这样的代码,它应该这样做:
local ln = 1
local skip = false
local mode = 0
local prev
for at, crlf in eaten:gmatch('()[\r\n]') do
local last = eaten:sub(at-1, at-1)
if skip and prev == last and last ~= crlf then
skip = false
else
skip = true
ln = ln + 1
end
prev = crlf
end
它决定是否吃的基础上,前一个字符换行。现在,从我所知道的情况来看,这个应该是的工作,但不管我做了什么,似乎都不起作用。其他尝试已经报告了5行,而这个报告是9(!)。我在这里错过了什么?我在Lua 5.2.4上运行这个。
这是用于解析\z
一个例程的一部分:用于重复的Lua脚本的线
local function parse52(s)
local startChar = string.sub(s,1,1)
if startChar~="'" and startChar~='"' then
error("not a string", 0)
end
local c = 0
local ln = 1
local t = {}
local nj = 1
local eos = #s
local pat = "^(.-)([\\" .. startChar .. "\r\n])"
local mkerr = function(emsg, ...)
error(string.format('[%s]:%d: ' .. emsg, s, ln, ...), 0)
end
local lnj
repeat
lnj = nj
local i, j, part, k = string.find(s, pat, nj + 1, false)
if i then
c = c + 1
t[c] = part
if simpleEscapes[v] then
--[[ some code, some elseifs, some more code ]]
elseif v == "z" then
local eaten, np = s:match("^([\t\n\v\f\r ]*)%f[^\t\n\v\f\r ]()", nj+1)
local p=np
nj = p-1
--[[ the newline counting routine above ]]
--[[ some other elseifs ]]
end
else
nj = nil
end
until not nj
if s:sub(-1, -1) ~= startChar then
mkerr("unfinished string near <eof>")
end
return table.concat(t)
end
答
紧凑代码:
local text = "First\n\r\n\r\r\n\n\nSixth"
local ln = 1
for line, newline in text:gmatch"([^\r\n]*)([\r\n]*)" do
print(ln, line)
ln = ln + #newline:gsub("\n+", "\0%0\0"):gsub(".%z.", "."):gsub("%z", "")
end
高效代码用于重复的Lua脚本的行:
local text = "First\n\r\n\r\r\n\n\nSixth"
local sub = string.sub
local ln = 1
for line, newline in text:gmatch'([^\r\n]*)([\r\n]*)' do
print(ln, line)
local pos, max_pos = 1, #newline
while pos <= max_pos do
local crlf = sub(newline, pos, pos + 1)
if crlf == "\r\n" or crlf == "\n\r" then
pos = pos + 2
else
pos = pos + 1
end
ln = ln + 1
end
end
'crlf' is总是'nil',因为'eaten:gmatch('()[\ r \ n]')'只返回一次捕获。可能你想让你的模式成为'()([\ r \ n])'? –
@EgorSkriptunoff解决了它,但我不能接受评论作为答案。 – SoniEx2
是的,这是SO的一个臭名昭着的错误特征:评论是不允许被接受的,尽管可能包含一个答案:-) –