mirror of
https://github.com/FourierTransformer/ftcsv.git
synced 2024-11-19 19:54:23 +00:00
Rename noQuotes to onlyRequiredQuotes and fix encoding bug (#35)
This commit is contained in:
parent
5be2f78119
commit
6238c5a0e8
@ -143,9 +143,9 @@ file:close()
|
|||||||
local output = ftcsv.encode(everyUser, ",", {fieldsToKeep={"Name", "Phone", "City"}})
|
local output = ftcsv.encode(everyUser, ",", {fieldsToKeep={"Name", "Phone", "City"}})
|
||||||
```
|
```
|
||||||
|
|
||||||
- `noQuotes`
|
- `onlyRequiredQuotes`
|
||||||
|
|
||||||
if `noQuotes` is set to `true`, the output will not include quotes around fields.
|
if `onlyRequiredQuotes` is set to `true`, the output will only include quotes around fields that are quotes, have newlines, or contain the delimter.
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
local output = ftcsv.encode(everyUser, ",", {noQuotes=true})
|
local output = ftcsv.encode(everyUser, ",", {noQuotes=true})
|
||||||
|
35
ftcsv.lua
35
ftcsv.lua
@ -645,15 +645,18 @@ local function delimitField(field)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function delimitAndQuoteField(field)
|
local function generateDelimitAndQuoteField(delimiter)
|
||||||
field = tostring(field)
|
local generatedFunction = function(field)
|
||||||
if field:find('"') then
|
field = tostring(field)
|
||||||
return '"' .. field:gsub('"', '""') .. '"'
|
if field:find('"') then
|
||||||
elseif field:find('[\n,]') then
|
return '"' .. field:gsub('"', '""') .. '"'
|
||||||
return '"' .. field .. '"'
|
elseif field:find('[\n' .. delimiter .. ']') then
|
||||||
else
|
return '"' .. field .. '"'
|
||||||
return field
|
else
|
||||||
|
return field
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
return generatedFunction
|
||||||
end
|
end
|
||||||
|
|
||||||
local function escapeHeadersForLuaGenerator(headers)
|
local function escapeHeadersForLuaGenerator(headers)
|
||||||
@ -681,7 +684,7 @@ local function csvLineGenerator(inputTable, delimiter, headers, options)
|
|||||||
delimiter .. [["' .. args.delimitField(args.t[i]["]]) ..
|
delimiter .. [["' .. args.delimitField(args.t[i]["]]) ..
|
||||||
[["]) .. '"\r\n']]
|
[["]) .. '"\r\n']]
|
||||||
|
|
||||||
if options and options.noQuotes == true then
|
if options and options.onlyRequiredQuotes == true then
|
||||||
outputFunc = [[
|
outputFunc = [[
|
||||||
local args, i = ...
|
local args, i = ...
|
||||||
i = i + 1;
|
i = i + 1;
|
||||||
@ -696,8 +699,8 @@ local function csvLineGenerator(inputTable, delimiter, headers, options)
|
|||||||
arguments.t = inputTable
|
arguments.t = inputTable
|
||||||
-- we want to use the same delimitField throughout,
|
-- we want to use the same delimitField throughout,
|
||||||
-- so we're just going to pass it in
|
-- so we're just going to pass it in
|
||||||
if options and options.noQuotes == true then
|
if options and options.onlyRequiredQuotes == true then
|
||||||
arguments.delimitField = delimitAndQuoteField
|
arguments.delimitField = generateDelimitAndQuoteField(delimiter)
|
||||||
else
|
else
|
||||||
arguments.delimitField = delimitField
|
arguments.delimitField = delimitField
|
||||||
end
|
end
|
||||||
@ -716,7 +719,7 @@ end
|
|||||||
|
|
||||||
local function initializeOutputWithEscapedHeaders(escapedHeaders, delimiter, options)
|
local function initializeOutputWithEscapedHeaders(escapedHeaders, delimiter, options)
|
||||||
local output = {}
|
local output = {}
|
||||||
if options and options.noQuotes == true then
|
if options and options.onlyRequiredQuotes == true then
|
||||||
output[1] = table.concat(escapedHeaders, delimiter) .. '\r\n'
|
output[1] = table.concat(escapedHeaders, delimiter) .. '\r\n'
|
||||||
else
|
else
|
||||||
output[1] = '"' .. table.concat(escapedHeaders, '"' .. delimiter .. '"') .. '"\r\n'
|
output[1] = '"' .. table.concat(escapedHeaders, '"' .. delimiter .. '"') .. '"\r\n'
|
||||||
@ -724,11 +727,11 @@ local function initializeOutputWithEscapedHeaders(escapedHeaders, delimiter, opt
|
|||||||
return output
|
return output
|
||||||
end
|
end
|
||||||
|
|
||||||
local function escapeHeadersForOutput(headers, options)
|
local function escapeHeadersForOutput(headers, delimiter, options)
|
||||||
local escapedHeaders = {}
|
local escapedHeaders = {}
|
||||||
local delimitField = delimitField
|
local delimitField = delimitField
|
||||||
if options and options.noQuotes == true then
|
if options and options.onlyRequiredQuotes == true then
|
||||||
delimitField = delimitAndQuoteField
|
delimitField = generateDelimitAndQuoteField(delimiter)
|
||||||
end
|
end
|
||||||
for i = 1, #headers do
|
for i = 1, #headers do
|
||||||
escapedHeaders[i] = delimitField(headers[i])
|
escapedHeaders[i] = delimitField(headers[i])
|
||||||
@ -771,7 +774,7 @@ local function initializeGenerator(inputTable, delimiter, options)
|
|||||||
end
|
end
|
||||||
validateHeaders(headers, inputTable)
|
validateHeaders(headers, inputTable)
|
||||||
|
|
||||||
local escapedHeaders = escapeHeadersForOutput(headers, options)
|
local escapedHeaders = escapeHeadersForOutput(headers, delimiter, options)
|
||||||
local output = initializeOutputWithEscapedHeaders(escapedHeaders, delimiter, options)
|
local output = initializeOutputWithEscapedHeaders(escapedHeaders, delimiter, options)
|
||||||
return output, headers
|
return output, headers
|
||||||
end
|
end
|
||||||
|
@ -61,15 +61,15 @@ describe("csv features", function()
|
|||||||
assert.are.same(expected, actual)
|
assert.are.same(expected, actual)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it("should handle escaped doublequotes", function()
|
it("should handle escaped doublequotes", function()
|
||||||
local expected = {}
|
local expected = {}
|
||||||
expected[1] = {}
|
expected[1] = {}
|
||||||
expected[1].a = 'A"B""C'
|
expected[1].a = 'A"B""C'
|
||||||
expected[1].b = 'A""B"C'
|
expected[1].b = 'A""B"C'
|
||||||
expected[1].c = 'A"""B""C'
|
expected[1].c = 'A"""B""C'
|
||||||
local actual = ftcsv.parse('a;b;c\n"A""B""""C";"A""""B""C";"A""""""B""""C"', ";", {loadFromString=true})
|
local actual = ftcsv.parse('a;b;c\n"A""B""""C";"A""""B""C";"A""""""B""""C"', ";", {loadFromString=true})
|
||||||
assert.are.same(expected, actual)
|
assert.are.same(expected, actual)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it("should handle renaming a field", function()
|
it("should handle renaming a field", function()
|
||||||
local expected = {}
|
local expected = {}
|
||||||
@ -435,25 +435,41 @@ describe("csv features", function()
|
|||||||
it("should handle encoding files (str test)", function()
|
it("should handle encoding files (str test)", function()
|
||||||
local expected = '"a","b","c","d"\r\n"1","","foo","""quoted"""\r\n'
|
local expected = '"a","b","c","d"\r\n"1","","foo","""quoted"""\r\n'
|
||||||
output = ftcsv.encode({
|
output = ftcsv.encode({
|
||||||
{ a = 1, b = '', c = 'foo', d = '"quoted"' };
|
{ a = 1, b = '', c = 'foo', d = '"quoted"' };
|
||||||
}, ',')
|
}, ',')
|
||||||
assert.are.same(expected, output)
|
assert.are.same(expected, output)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("should handle encoding files (str test) with other delimiter", function()
|
||||||
|
local expected = '"a">"b">"c">"d"\r\n"1">"">"foo">"""quoted"""\r\n'
|
||||||
|
output = ftcsv.encode({
|
||||||
|
{ a = 1, b = '', c = 'foo', d = '"quoted"' };
|
||||||
|
}, '>')
|
||||||
|
assert.are.same(expected, output)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it("should handle encoding files without quotes (str test)", function()
|
it("should handle encoding files without quotes (str test)", function()
|
||||||
local expected = 'a,b,c,d\r\n1,,foo,"""quoted"""\r\n'
|
local expected = 'a,b,c,d\r\n1,,"fo,o","""quoted"""\r\n'
|
||||||
output = ftcsv.encode({
|
output = ftcsv.encode({
|
||||||
{ a = 1, b = '', c = 'foo', d = '"quoted"' };
|
{ a = 1, b = '', c = 'fo,o', d = '"quoted"' };
|
||||||
}, ',', {noQuotes=true})
|
}, ',', {onlyRequiredQuotes=true})
|
||||||
assert.are.same(expected, output)
|
assert.are.same(expected, output)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("should handle encoding files without quotes with other delimiter (str test)", function()
|
||||||
|
local expected = 'a>b>c>d\r\n1>>fo,o>"""quoted"""\r\n'
|
||||||
|
output = ftcsv.encode({
|
||||||
|
{ a = 1, b = '', c = 'fo,o', d = '"quoted"' };
|
||||||
|
}, '>', {onlyRequiredQuotes=true})
|
||||||
|
assert.are.same(expected, output)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it("should handle encoding files without quotes with certain fields to keep (str test)", function()
|
it("should handle encoding files without quotes with certain fields to keep (str test)", function()
|
||||||
local expected = "b,c\r\n,foo\r\n"
|
local expected = "b,c\r\n,foo\r\n"
|
||||||
output = ftcsv.encode({
|
output = ftcsv.encode({
|
||||||
{ a = 1, b = '', c = 'foo', d = '"quoted"' };
|
{ a = 1, b = '', c = 'foo', d = '"quoted"' };
|
||||||
}, ',', {noQuotes=true, fieldsToKeep={"b", "c"}})
|
}, ',', {onlyRequiredQuotes=true, fieldsToKeep={"b", "c"}})
|
||||||
assert.are.same(expected, output)
|
assert.are.same(expected, output)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it("should handle headers attempting to escape", function()
|
it("should handle headers attempting to escape", function()
|
||||||
|
@ -94,7 +94,7 @@ describe("csv encode without quotes", function()
|
|||||||
local jsonFile = loadFile("spec/json/" .. value .. ".json")
|
local jsonFile = loadFile("spec/json/" .. value .. ".json")
|
||||||
local jsonDecode = cjson.decode(jsonFile)
|
local jsonDecode = cjson.decode(jsonFile)
|
||||||
-- local parse = staecsv:ftcsv(contents, ",")
|
-- local parse = staecsv:ftcsv(contents, ",")
|
||||||
local reEncodedNoQuotes = ftcsv.parse(ftcsv.encode(jsonDecode, ",", {noQuotes=true}), ",", {loadFromString=true})
|
local reEncodedNoQuotes = ftcsv.parse(ftcsv.encode(jsonDecode, ",", {onlyRequiredQuotes=true}), ",", {loadFromString=true})
|
||||||
-- local f = csv.openstring(contents, {separator=",", header=true})
|
-- local f = csv.openstring(contents, {separator=",", header=true})
|
||||||
-- local parse = {}
|
-- local parse = {}
|
||||||
-- for fields in f:lines() do
|
-- for fields in f:lines() do
|
||||||
|
Loading…
Reference in New Issue
Block a user