「第2回エンペディア大賞」が2月いっぱい開催中です。2024年に作成された記事の中から、お気に入りの記事に投票しましょう!
モジュール:CSV
ナビゲーションに移動
検索に移動
local p = {}
-- ダブルクォートの囲み有り、ダブルクォートエスケープ有り
--(RFC4180に部分的に準拠)
function p.toArr2D(args)
local csv = args[1]
if csv == nil then return {} end
local maxStep = args.maxStep or 1000 -- 最大セル解釈数
local tbl = {}
local row = {}
-- パフォーマンス最適化のため変数宣言をfor文の外に
local cellTxt = ''
local start = 0 -- セル内容の開始idx
local stop = 0 -- セル内容の終了idx
local isLf = false
local cursor = 1
for i = 1, maxStep do -- maxStepステップ以上のループ拒否
cellTxt = ''
isLf = false
-- ダブルクォート ~ ダブルクォート(改行|カンマ) にマッチ
start, stop = csv:find('^".-"[\n,]', cursor)
if start ~= nil then
cursor = stop + 1
isLf = csv:sub(stop, stop) == '\n'
start = start + 1
stop = stop - 2
else
-- ダブルクォート ~ ダブルクォート終端 にマッチ
start, stop = csv:find('^".-"$', cursor)
if start ~= nil then
cursor = stop + 1
isLf = true
start = start + 1
stop = stop - 1
else
-- ~ (改行|カンマ) にマッチ
start, stop = csv:find('.-[\n,]', cursor)
if start ~= nil then
cursor = stop + 1
isLf = csv:sub(stop, stop) == '\n'
stop = stop - 1
else -- 何にもマッチしない
start = cursor
cursor = #csv + 1
isLf = true
stop = cursor - 1
end
end
end
-- セル内容を取得
cellTxt = csv:sub(start, stop):gsub('""', '"')
table.insert(row, cellTxt)
if isLf then
table.insert(tbl, row)
row = {}
end
if #csv < cursor then break end
end
return tbl
end
-- p.toTbl関数の動作確認用
-- WikiText上で {{#invoke:CSV|toTblPrint|csv=a,b,c}} のように呼び出せる
function p.toArr2DPrint(frame)
local args = require('Module:Arguments').getArgs(frame)
local csv = args[1] or args.csv
if csv == nil then return '<<csv arg is nil!>>' end
local tbl = p.toArr2D({csv})
body = '<pre>'
for rowIdx, row in pairs(tbl) do
for colIdx, col in pairs(row) do
body = body..'<<'..col..'>>'
end
body = body..'((改行))\n'
end
return frame:preprocess( body..' len: '..#tbl..'</pre>' )
end
-- ダブルクォートの囲み無し、ダブルクォートエスケープ無し
function p.csv2tbl(args)
local csv = args[1]
if csv == nil then return {} end
local tbl = {}
local row = {}
local rowIdx = 1
for line, lf in csv:gmatch '([^\n]+)(\n*)' do
row.lf = lf
local colIdx = 1
local isLast = false
for cell, comma in line:gmatch '([^,]*)(,?)' do
-- セルの情報をrowに溜める
if not isLast then row[colIdx] = cell end
isLast = #comma == 0
colIdx = colIdx + 1
if colIdx > 1000 then break end -- 1000列より大きい処理を拒否
end
-- 1行分の情報をtblの末尾に追加
if 0 < #row then table.insert(tbl, row) end
row = {}
rowIdx = rowIdx + 1
if rowIdx > 1000 then break end -- 1000行より大きい処理を拒否
end
return tbl
end
return p