模块:Csv.lua:修订间差异

来自「荏苒之境」
无编辑摘要
无编辑摘要
第38行: 第38行:
             local s, e, text, c1 = string.find(
             local s, e, text, c1 = string.find(
                 input, "^([^%"..sep.."\r\n]-)([%"..sep.."\r\n])", pos)
                 input, "^([^%"..sep.."\r\n]-)([%"..sep.."\r\n])", pos)
            print(s, e, text, c1)
             pos = e+1
             pos = e+1
             table.insert(row, text)
             table.insert(row, text)
             c = c1
             c = c1
         end
         end
         if c == "\n" then return row, pos
         if c == "\n" then
         elseif c == "\r" then return row, pos+1 end
        return row, pos
         elseif c == "\r" then
        return row, pos+1
        end
     end
     end
end
end

2025年8月1日 (五) 23:21的版本

此模块的文档可以在模块:Csv.lua/doc创建

--[[
    CSV Library v1 (Author: Michael Lutz, 2022-12-14)
    Built on: http://lua-users.org/wiki/LuaCsv
    
    csv.load = function(filename, delimiter, header)
    filename := CSV file to load
    delimiter := Delimiter (";", ",", "\t", etc..), default = ','
    header := (optional) if first line is a header (true/false), default = false
    
    automatically removes quotes from text
    returns a table
    
    csv.save = function(filename, delimiter, data, header)
    filename := CSV file to write to
    delimiter := Delimiter (";", ",", "\t", etc..), default = ','
    data := a Lua table that holds the rows and columns
    header := a Lua table that holds the names of the columns e.g. { "Name", "Address", "Email", ... }
--]]

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)
            print(s, e, text, c1)
            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(str, delimiter, header)
    local sep = delimiter and 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(str, 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(str, sep, pos)
    while row do
        if header then
            setmetatable(row, { __index = f_header })
        end
        table.insert(t_csv, row)
        row, pos = parse_row(str, 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