最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

csv - reading delimited text file into Lua table - Stack Overflow

programmeradmin2浏览0评论

I have a file, something of this sort (CSV, TSV: delimited text):

"col1","col2","col3"
"1","ab","6.5"
"4","df","9.7"

I would like to read it to the Lua's table with named fields (like Python's list of dictionaries). Something of this sort:

{
  {'col1'='1', 'col2'='ab', 'col3'='6.5'},
  {'col1'='4', 'col2'='df', 'col3'='9.7'}
}

In the end I should be able to access the data in the following way:

t[1].col1
t[1].col2
or
t[2].col3

I cannot get my head around Lua's syntax on this matter. Unfortunately various modules working with CSV are not really usable for me in this case. Because it will not be supported by application. It should be Lua's simple solution. Here is my attempt, but it does not work.

    local function split(str, sep)
       local t={}
       for s in string.gmatch(str, "([^"..sep.."]+)") do
          table.insert(t,s)
       end
       return t
    end

    local t_line = {}
    local t_row = {}
    local t_header = {}
    local t_target = {}
    local i = 1
    for line in io.lines('some_file.txt') do
        t_line = split(line, ',')
        for j=1, #t_line do
            if i == 1 then -- first line of the file
                -- read header into table
                table.insert(t_header, t_line[j])
            else
                -- this suppose to tell that t_header[j] is the key
                -- and t_line[j] is its value
                table.insert(t_row, [t_header[j]] = t_line[j])
            end
        end
        -- here I add table as a row into main table
        if i > 1 then
            table.insert(t_target, t_row)
        end
        i = i + 1
    end

This part does not work:

table.insert(t_row, [t_header[j]] = t_line[j])

Execution of the script throws an error:

lua: ./example_10.lua:28: unexpected symbol near '['

but I tried to remove square brackets and it starts complaining about equal sign. Here is the way that line works:

table.insert(t_row, t_line[j])

but then I will not able to call element by key name only by index. How to add value to the table and name the key by column name?

I have a file, something of this sort (CSV, TSV: delimited text):

"col1","col2","col3"
"1","ab","6.5"
"4","df","9.7"

I would like to read it to the Lua's table with named fields (like Python's list of dictionaries). Something of this sort:

{
  {'col1'='1', 'col2'='ab', 'col3'='6.5'},
  {'col1'='4', 'col2'='df', 'col3'='9.7'}
}

In the end I should be able to access the data in the following way:

t[1].col1
t[1].col2
or
t[2].col3

I cannot get my head around Lua's syntax on this matter. Unfortunately various modules working with CSV are not really usable for me in this case. Because it will not be supported by application. It should be Lua's simple solution. Here is my attempt, but it does not work.

    local function split(str, sep)
       local t={}
       for s in string.gmatch(str, "([^"..sep.."]+)") do
          table.insert(t,s)
       end
       return t
    end

    local t_line = {}
    local t_row = {}
    local t_header = {}
    local t_target = {}
    local i = 1
    for line in io.lines('some_file.txt') do
        t_line = split(line, ',')
        for j=1, #t_line do
            if i == 1 then -- first line of the file
                -- read header into table
                table.insert(t_header, t_line[j])
            else
                -- this suppose to tell that t_header[j] is the key
                -- and t_line[j] is its value
                table.insert(t_row, [t_header[j]] = t_line[j])
            end
        end
        -- here I add table as a row into main table
        if i > 1 then
            table.insert(t_target, t_row)
        end
        i = i + 1
    end

This part does not work:

table.insert(t_row, [t_header[j]] = t_line[j])

Execution of the script throws an error:

lua: ./example_10.lua:28: unexpected symbol near '['

but I tried to remove square brackets and it starts complaining about equal sign. Here is the way that line works:

table.insert(t_row, t_line[j])

but then I will not able to call element by key name only by index. How to add value to the table and name the key by column name?

Share Improve this question edited Feb 15 at 20:55 user22099079 asked Feb 15 at 20:26 user22099079user22099079 531 silver badge4 bronze badges New contributor user22099079 is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct. 3
  • Here is a canonical question: stackoverflow/questions/41585078/… – Walter Mitty Commented Feb 16 at 14:08
  • @WalterMitty, as there's no apparent reference to lua in that is it relevant ? – ticktalk Commented Feb 16 at 14:39
  • @WalterMitty -- that has nothing to do with this question. As I addressed in my answer, OP code has a syntax mistake which led to the error they reported, and a misplaced table definition which would lead to incorrect behavior if the syntax mistake were corrected. These are programming issues, particular to Lua, and not related to Python or reading CSV files in general. – ad absurdum Commented Feb 16 at 15:31
Add a comment  | 

1 Answer 1

Reset to default 3

table.insert needs a value to insert into the table, but [t_header[j]] = t_line[j] is not a value; this looks a like a misapplication of table constructor syntax. In any case this is a syntax violation: you can only use table constructor syntax in a table constructor. It sort of looks like an assignment statement, which might confuse someone who comes from C which has assignment expressions which evaluate to the value of the assignment.

The OP code could most simply be fixed by changing:

table.insert(t_row, [t_header[j]] = t_line[j])

to:

t_row[t_header[j]] = t_line[j]

This sets the fields of t_row to the right values before inserting the rows into the t_target table. There is no need for table.insert here. To complete the fix, the line local t_row = {} would also need to be moved inside the outer loop so that a new row table is created for each line.

Still, the design of the posted code seems a little more complicated than it needs to be. Here is an adjusted version that uses the OP posted split function. The parse_csv function parses an input file into a table. Here the iterator returned by io.lines is saved in lines and called once to get the headers first, then the iterator is called in a loop to get the remainder of the lines from the file.

I have added a simple csv_dump function to print the contents of the parsed csv table.

function parse_csv(f)
   local parsed_csv = {}
   local lines = io.lines(f)
   local labels = split(lines(), ",")
   for line in lines do
      local t_line = split(line, ",")
      local t_row = {}
      for k, v in ipairs(t_line) do
         t_row[labels[k]] = v
      end
      table.insert(parsed_csv, t_row)
   end
   return parsed_csv
end

function csv_dump(t)
   for i, row in ipairs(t) do
      io.write(i)
      io.write(" { ")
      for k, v in pairs(row) do
         io.write(k, "=", v, " ")
      end
      print("}")
   end
end

Sample usage:

> parsed = parse_csv('csv_test.txt')
> csv_dump(parsed)
1 { "col3"="6.5" "col2"="ab" "col1"="1" }
2 { "col3"="9.7" "col2"="df" "col1"="4" }
发布评论

评论列表(0)

  1. 暂无评论