LuaTeXについて3(パッケージの作り方)

今回はLuaTeXの機能を使ったパッケージを作成する。 LuaTeX用のパッケージを作るということはLuaが使えるということである。 これはだいぶ喜ばしい事だろう、多分。 というのも、普通のplatex用のパッケージもろくに作った事ないので、 嬉しさがピンとこない。 それはさておき、Luaの機能を使ってパッケージが作れる。 Luaにあって、TeX単体では難しい作業ということで、 今回は.csvファイルから表を作成するパッケージを作る事にする。 \csvToTable{"filename.csv"}と書くと、 filename.csvを読み込んで、tabular環境の表を作ってくれる関数をつくる。 TeX単体でできるとかできないとかは不明。 とりあえず奥村先生の本にはのってない。 Luaには標準のfile ioが備わっているので簡単にできるはずである。 csvをパースするのはLuaの公式HPから拝借する

function fromCSV (s)
  -- 公式のHPより拝借
  s = s .. ','        -- ending comma
  local t = {}        -- table to collect fields
  local fieldstart = 1
  repeat
    -- next field is quoted? (start with `"'?)
    if string.find(s, '^"', fieldstart) then
      local a, c
      local i  = fieldstart
      repeat
        -- find closing quote
        a, i, c = string.find(s, '"("?)', i+1)
      until c ~= '"'    -- quote not followed by quote?
      if not i then error('unmatched "') end
      local f = string.sub(s, fieldstart+1, i-1)
      table.insert(t, (string.gsub(f, '""', '"')))
      fieldstart = string.find(s, ',', i) + 1
    else                -- unquoted; find next comma
      local nexti = string.find(s, ',', fieldstart)
      table.insert(t, string.sub(s, fieldstart, nexti-1))
      fieldstart = nexti + 1
    end
  until fieldstart > string.len(s)
  return t
end
これでコンマで区切られたデータを分割できる。 次にファイルを読み込んで各行を上の関数に渡す関数を作る。 file ioに関してはこのあたりが詳しい。

function readCSV(filename)
    local f = assert(io.open(filename,'r'))
    data = {}
    count = 1
    while true do
        line = f:read("*line")
        if line == nil then break end
        list = fromCSV(line)
        data[count] = list
        count = count + 1
    end
    return data
end
これでファイルを読み込んで、csvをパースする所までできた。 Luaの基本的な機能だけでごくごく簡単な作業だ。 さていよいよパースしたデータから表を作成する

function csvToSimpleTable(filename)
    data = readCSV(filename)
    -- とりあえず先頭のdataの要素にあわせておく
    local len = #data[1]
    local tab = '{'
    for i = 1,len do
        tab = tab .. "r"
    end
    tab = tab .. '}'
    tex.print("\\begin{tabular}" .. tab)
    for i,list in ipairs(data) do
        local line = ""
        for j,val in ipairs(list) do
            if line == "" then 
                line = val
            else
                line = line .. '&' .. val
            end
        end
        tex.print(line .. '\\\\')
    end
    tex.print("\\end{tabular}")
end
LuaからTeXの入力を行うにはtex.print(...)を用いる。 Luaでは文字列の合成は..で行うことと、#dataがデータの個数 (pythonでいえばlen(data))になっていること、 LaTeXの文字列をエスケープする必要がある事に注意すれば、 そう変なことはしていない。 これでLuaの方は完成である。 TeXの方は.dtxと.insファイルを作る。 これについては次回まとめる事にする。 特にLuaTeX用に工夫すべき点は、上記の関数の書いてある.luaをどこで読み込むかで、 .dtxの上の方でのように書くといいと思う。

%\directlua{dofile('csvReader.lua')}
あとは普通に

\newcommand\csvToSimpleTable[1]{\directlua{csvToSimpleTable(#1)}}
のように定義すれば使える。 >>4に続く。