模块:Csv.lua

来自「荏苒之境」
Sicusa留言 | 贡献2025年8月1日 (五) 23:10的版本 (页面内容被替换为“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…”)

此模块的文档可以在模块: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