Module:CSV

local p = {} default_settings = { delimiter = ',', quotechar = '"', ignoreEmptyLines = true,  --linebreak deviates from RFC4180, where the default linebreak is CRLF. Mediawiki newlines are linebreaks  linebreak = '\n' } --datastring is the string containing the CSV data. settings follows the format of default_settings --returns a table which is a squence of sequeces of fields function parse(datastring, settings)  if settings == nil then settings = {} end  if type(settings) ~= 'table' then return {}, "Error, settings is not a table" end  for k, v in pairs(default_settings) do    if settings[k] == nil then settings[k] = default_settings[k] end  end  return readdata(datastring, settings) end function readdata(datastring, settings)    datastring = datastring:gsub( settings.linebreak, settings.linebreak .. settings.delimiter ) .. settings.delimiter;    local item_list = {};    for v in datastring:gmatch( "([^" .. settings.delimiter .."]*)" .. settings.delimiter ) do       table.insert( item_list, v );    end    local item_list2 = {};    local current = ''    local inquote = false    for _, v in ipairs( item_list ) do        if not inquote then            if v:match( "^%s*" .. settings.quotechar ) then               inquote = true;                current = v;            else                table.insert( item_list2, v );            end        else            current = current .. settings.delimiter .. v;        end        if inquote then            if v:match( settings.quotechar .. "%s*$" ) and not current:match( "^%s*" .. settings.quotechar .. "%s*$" ) then               current = current:match( "^%s*" .. settings.quotechar .. "(.*)" .. settings.quotechar .. "%s*$" );               current = current:gsub( settings.linebreak .. settings.delimiter, settings.linebreak );               current = current:gsub( settings.quotechar .. settings.quotechar, settings.quotechar );               table.insert( item_list2, current );                inquote = false;                current = ;            end                    end    end    if current ~=  then        table.insert( item_list2, current );    end    local rows = {};    item_list = {};    local front = ''    for _, v in ipairs(item_list2) do        front = v:match( "(.*)" .. settings.linebreak .. "$" );       if front ~= nil then            if #item_list > 0 or front:len > 0 or not settings.ignoreEmptyLines then                 table.insert( item_list, front )                table.insert( rows, item_list );            end            item_list = {};        else            table.insert( item_list, v );        end    end    if #item_list > 0 then        table.insert( rows, item_list );    end    return rows; end p.parse = parse return p