Skip to content

Instantly share code, notes, and snippets.

@dohyunkim
Last active January 8, 2016 13:37
Show Gist options
  • Select an option

  • Save dohyunkim/ff37e969def2a6fa85f7 to your computer and use it in GitHub Desktop.

Select an option

Save dohyunkim/ff37e969def2a6fa85f7 to your computer and use it in GitHub Desktop.
read csv and print latex tabular
readcsv = readcsv or {}
local readcsv = readcsv
local function readcsvlines (s, sep)
sep = sep or ','
s = s .. "\n"
s = s:gsub("[\r\n]+", "\n") -- unix newline
local curr, t = 1, {{}}
while true do
local tt, i, a, c = t[#t], curr
if s:find('^"', curr) then -- starts with doublequote
repeat
a, i, c = s:find('"(.)', i+1) -- "" or ", or "\n
until c ~= '"'
tt[#tt+1] = s:sub(curr+1, a-1):gsub('""', '"') -- restore double doublequotes
else
a, i, c = s:find("(["..sep.."\n])", curr)
tt[#tt+1] = s:sub(curr, a-1)
end
curr = i + 1
if curr > s:len() then break end
if c == "\n" then t[#t+1] = {} end -- prepare another line
end
return t
end
-- http://www.lua.org/pil/20.4.html
-- https://tools.ietf.org/html/rfc4180#section-2
local function readcsvfile (f, sep)
local fh = io.open(kpse.find_file(f), "r")
local t = readcsvlines(fh:read("*all"), sep)
fh:close()
return t
end
local function parse_option (opt, s, length)
s = s .. ","
local curr = 1
while true do
local k, v, i
_, i, k = s:find("%s*([^,]-)%s*=%s*", curr)
if not i then break end
curr = i + 1
_, i, v = s:find("^(%b{})%s*,+", curr)
if i then
v = v:gsub("^{(.-)}$", "%1")
else
_, i, v = s:find("(.-)%s*,+", curr)
end
curr = i + 1
if k and v and k ~= "" then
local row = k:match("^afterrow(.+)")
if row == "*" then
for l=0, length do
opt.afterrow[l] = v
end
elseif row then
opt.afterrow[tonumber(row)] = v
else
opt[k] = v
end
end
end
return opt
end
local function select_cols (t, cols)
if not cols or cols == "" then return t end
cols = cols:explode(",+")
for i, v in ipairs(cols) do
cols[i] = tonumber(v)
end
local tt = {}
for i, v in ipairs(t) do
tt[i] = {}
for _, c in ipairs(cols) do
tt[i][#tt[i]+1] = t[i][c]
end
end
return tt
end
local function skip_rows (rows)
local t = {}
if not rows or rows == "" then return t end
rows = rows:explode(",+")
for _, v in ipairs(rows) do
t[tonumber(v)] = true
end
return t
end
local catreg = { string = -2, latex = -1, }
local function csv2tabular(f, sep, op)
local t = readcsvfile(f, sep)
local opt = {
header = "\\begin{tabular}{"..string.rep("r", #t[1]).."}",
footer = "\\end{tabular}",
afterrow = { [0] = "\\hline", [1] = "\\hline", [#t] ="\\hline" },
catcode = "string", -- string or latex
crlf = " ",
newline = "\\\\",
}
opt = parse_option(opt, op, #t)
t = select_cols(t, opt.columns)
local skiprows = skip_rows(opt.skiprows)
-- now print tablular
tex.sprint(opt.header)
if opt.afterrow[0] then tex.sprint(opt.afterrow[0]) end
for i, v in ipairs(t) do
if not skiprows[i] then
for ii, vv in ipairs(v) do
tex.tprint({catreg[opt.catcode], (vv:gsub("\n", opt.crlf))},
{ii < #v and "&" or opt.newline})
end
if opt.afterrow[i] then tex.sprint(opt.afterrow[i]) end
end
end
tex.sprint(opt.footer)
end
readcsv.tabular = csv2tabular
\ProvidesPackage{readcsv}[2016/01/01 v0.0 CSV to tabular]
\directlua{require "readcsv"}
\protected\def\csvtabular{\def\csv@separator{,}\futurelet\next\csv@tabular}
\protected\def\tsvtabular{\def\csv@separator{\string\t}\futurelet\next\csv@tabular}
\def\csv@tabular{%
\ifx[\next
\expandafter\csv@@tabular
\else
\expandafter\csv@@tabular\expandafter[\expandafter]%
\fi
}
\def\csv@@tabular[#1]#2{\directlua{%
readcsv.tabular("#2", "\csv@separator", "\luaescapestring\expandafter{\detokenize{#1}}")
}}
\endinput
% csvtabular[options]{file}
% tsvtabular[options]{file}
%
% option examples:
%
% header=\begin{tabular}{rrr},
% footer=\end{tabular},
%
% columns={1,4,5}, select columns to print. default: all columns.
%
% afterrow0=\hline, tex code inserted before first line.
% afterrow1=\hline, tex code inserted after first line.
% afterrow2=, tex code inserted after second line.
% afterrow*=\hline, tex code inserted after each and every line.
%
% newline=\\, tabular new line.
%
% crlf={ }, endline char in csv data will be converted to space.
%
% catcode=string, latex: allow tex commands. string: prints verbatim.
@dohyunkim
Copy link
Author

\documentclass{article}
\usepackage{readcsv}
\begin{document}
\begin{table}\centering\caption{CSV Table Test}
  \csvtabular[align=crrrr]{civil-gdp-pop.csv}
\end{table}
\end{document}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment