| 1 | local lpeg = require "lpeg" |
| 2 | local setmetatable, tonumber = |
| 3 | setmetatable, tonumber; |
| 4 | local s_char = string.char; |
| 5 | |
| 6 | module("tsv"); |
| 7 | |
| 8 | local delim = lpeg.P"\t"; |
| 9 | |
| 10 | local char_escape = lpeg.R"az" + lpeg.S"\\\r\n" + delim; |
| 11 | local numeric_escape = (lpeg.R"09"^1)^-3; |
| 12 | local escape = (lpeg.P"\\" * (char_escape + numeric_escape)); |
| 13 | |
| 14 | local value = (escape + (1-delim))^0; |
| 15 | |
| 16 | local escape_map = setmetatable({ |
| 17 | t = "\t", b = "\b", f = "\f"; |
| 18 | n = "\n", r = "\r", v = "\v"; }, |
| 19 | { __index = function (_, n) |
| 20 | if tonumber(n) then |
| 21 | print"n" |
| 22 | return s_char(tonumber(n)); |
| 23 | else |
| 24 | return n; |
| 25 | end |
| 26 | end |
| 27 | }); |
| 28 | |
| 29 | function read_record(line, value_callback) |
| 30 | local fieldpos = 0; |
| 31 | local callback = function (v) |
| 32 | return value_callback(v:gsub("\\(.)", escape_map)); |
| 33 | end; |
| 34 | repeat |
| 35 | fieldpos = lpeg.match(value / callback, line, fieldpos+1); |
| 36 | until fieldpos >= #line; |
| 37 | end |
| 38 | |
| 39 | return _M; |