96 lines
2.2 KiB
Lua
96 lines
2.2 KiB
Lua
local input = arg[1]
|
|
local output = arg[2]
|
|
|
|
local f = assert(io.open(input, "r"))
|
|
local s = f:read("*a")
|
|
f:close()
|
|
|
|
local delim = ","
|
|
local out, row = {}, {}
|
|
local i, n = 1, #s
|
|
|
|
local function csv_escape(cell)
|
|
local needs_quotes =
|
|
cell:find(delim, 1, true) or cell:find('"', 1, true) or
|
|
cell:find("\\ ", 1, true) or cell:find("[\r\n]", 1, true)
|
|
if needs_quotes then
|
|
cell = cell:gsub('"','""')
|
|
return '"' .. cell .. '"'
|
|
end
|
|
return cell
|
|
end
|
|
|
|
local function push_cell(cell) row[#row+1] = cell end
|
|
local function end_row() out[#out+1] = row; row = {} end
|
|
|
|
while i <= n do
|
|
local c = s:sub(i,i)
|
|
|
|
if c == '"' then
|
|
i = i + 1
|
|
local buf = {}
|
|
while i <= n do
|
|
c = s:sub(i,i)
|
|
if c == '"' then
|
|
local nextc = s:sub(i+1,i+1)
|
|
if nextc == '"' then
|
|
buf[#buf+1] = '"'
|
|
i = i + 2
|
|
else
|
|
i = i + 1
|
|
break
|
|
end
|
|
else
|
|
buf[#buf+1] = c
|
|
i = i + 1
|
|
end
|
|
end
|
|
local cell = table.concat(buf)
|
|
cell = cell:gsub("\r\n","\\\\{}")
|
|
cell = cell:gsub("\n","\\\\{}")
|
|
cell = cell:gsub("\r","\\\\{}")
|
|
push_cell(cell)
|
|
|
|
local c2 = s:sub(i,i)
|
|
if c2 == delim then i = i + 1
|
|
elseif c2 == "\n" then i = i + 1; end_row()
|
|
elseif c2 == "\r" then
|
|
if s:sub(i+1,i+1) == "\n" then i = i + 2 else i = i + 1 end
|
|
end_row()
|
|
end
|
|
else
|
|
local buf = {}
|
|
while i <= n do
|
|
c = s:sub(i,i)
|
|
if c == delim or c == "\n" or c == "\r" then break end
|
|
buf[#buf+1] = c
|
|
i = i + 1
|
|
end
|
|
local cell = table.concat(buf)
|
|
cell = cell:gsub("\r\n","\\\\{}")
|
|
cell = cell:gsub("\n","\\\\{}")
|
|
cell = cell:gsub("\r","\\\\{}")
|
|
push_cell(cell)
|
|
|
|
if i <= n and s:sub(i,i) == delim then i = i + 1
|
|
elseif i <= n and s:sub(i,i) == "\n" then i = i + 1; end_row()
|
|
elseif i <= n and s:sub(i,i) == "\r" then
|
|
if s:sub(i+1,i+1) == "\n" then i = i + 2 else i = i + 1 end
|
|
end_row()
|
|
end
|
|
end
|
|
end
|
|
|
|
if #row > 0 then end_row() end
|
|
|
|
local fo = assert(io.open(output, "w"))
|
|
for r = 1, #out do
|
|
local cells = out[r]
|
|
for k = 1, #cells do
|
|
if k > 1 then fo:write(delim) end
|
|
fo:write(csv_escape(cells[k] or ""))
|
|
end
|
|
if r < #out then fo:write("\n") end
|
|
end
|
|
fo:close()
|