解析Lua字符串,更具体地讲是换行符

我正在尝试解析Lua 5.3字符串。但是,我遇到了问题。例如,

$ lua
Lua 5.3.4 版权所有(C) 1994-2017 Lua.org, PUC-Rio
> print(load('return "\\z \n\r \n\r \r\n \n \n \\x"', "@test"))
nil test:6: 在"\x"附近需要十六进制数字
>
> print(load('return "\\z\n\r\n\r\r\n\n\n\\x"', "@test"))
nil test:6: 在"\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的一部分:

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
        --[[ 某些代码,某些elseif,更多代码 ]]
      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
        --[[ 上面的换行计数例程 ]]
        --[[ 其他某些elseif ]]
      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
点赞
用户1847592
用户1847592

紧凑的代码遍历 Lua 脚本中的行:

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
2017-10-14 19:48:33