模块:Csv.lua
来自「荏苒之境」
此模块的文档可以在模块:Csv.lua/doc创建
local function parse_row(input, sep, pos)
local row = {}
local pos = pos or 1
while true do
local c = string.sub(input, pos, pos)
if c == "" then break end
if c == '"' then
local text = ''
local s, e, txt, c1
repeat
s, e, txt, c1 = string.find(input, '^(.-")(.)', pos + 1)
text = text..txt
pos = e
until c1 == sep or c1 == "\r" or c1 == "\n"
table.insert(row, string.sub(text, 1, -2))
c = c1
pos = pos + 1
else
local s, e, text, c1 = string.find(
input, "^([^%"..sep.."\r\n]-)([%"..sep.."\r\n])", pos)
pos = e+1
table.insert(row, text)
c = c1
end
if c == "\n" then return row, pos
elseif c == "\r" then return row, pos+1 end
end
end
local csv = {}
csv.parse = function(src, delimiter, header)
local sep = string.sub(delimiter,1,1) or ','
local pos = 1
local t_csv = {}
local f_header = nil
local t_header = {}
if header then
t_header,pos = parse_row(src, sep, pos)
local head = {}
for i,v in ipairs(t_header) do
head[v] = i
end
f_header = function (t,k)
local i = head[k]
if i then
return t[i]
end
return nil
end
end
local row = {}
row, pos = parse_row(src, sep, pos)
while row do
if header then
setmetatable(row, { __index = f_header })
end
table.insert(t_csv, row)
row, pos = parse_row(csv, sep, pos)
end
return t_csv, t_header
end
local function format_csv(str, sep)
local str, matches = string.gsub(str or "", '"', '""')
if (string.find(str, "[%"..sep.."\r\n]") or (matches > 0)) then
return '"'..str..'"'
end
return str
end
csv.format = function(delimiter, data, header)
local r = {}
local sep = string.sub(delimiter,1,1) or ','
if header then
for i,v in ipairs(header) do
r[#r+1] = format_csv(v, sep)
r[#r+1] = sep
end
r[#r] = "\n"
end
for i,v in ipairs(data) do
for i2,v2 in ipairs(v) do
r[#r+1] = format_csv(v2, sep)
r[#r+1] = sep
end
r[#r] = "\n"
end
return table.concat(r)
end
return csv