mirror of
https://github.com/FourierTransformer/ftcsv.git
synced 2024-11-19 19:54:23 +00:00
Added rowFunc as optional parameter to ftcsv.parse
rowFunc will be called after parsing each data row as follows: output[line] = rowFunc(output[line], line) if output[line] is nil afterwards, line will not be incremented.
This commit is contained in:
parent
4a2c22fb0a
commit
7bdd4aa5bd
16
README.md
16
README.md
@ -70,6 +70,22 @@ ftcsv.parse("apple,banana,carrot", ",", {loadFromString=true, headers=false})
|
|||||||
local actual = ftcsv.parse("a,b,c\napple,banana,carrot", ",", options)
|
local actual = ftcsv.parse("a,b,c\napple,banana,carrot", ",", options)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
- `rowFunc`
|
||||||
|
|
||||||
|
Applies a function to every row in the dataset. `rowFunc` will be passed a table containing the data for the row, and the row number. It should return a table which will be used in place of the original data table, or `nil` to remove the row entirely.
|
||||||
|
|
||||||
|
Ex: making field `a` uppercase
|
||||||
|
```lua
|
||||||
|
local options = {
|
||||||
|
loadFromString=true,
|
||||||
|
rowFunc=function(row, num)
|
||||||
|
row.a = string.upper(row.a)
|
||||||
|
return row
|
||||||
|
end
|
||||||
|
}
|
||||||
|
local actual = ftcsv.parse("a,b,c\napple,banana,carrot", ",", options)
|
||||||
|
```
|
||||||
|
|
||||||
- `headers`
|
- `headers`
|
||||||
|
|
||||||
Set `headers` to `false` if the file you are reading doesn't have any headers. This will cause ftcsv to create indexed tables rather than a key-value tables for the output.
|
Set `headers` to `false` if the file you are reading doesn't have any headers. This will cause ftcsv to create indexed tables rather than a key-value tables for the output.
|
||||||
|
27
ftcsv.lua
Normal file → Executable file
27
ftcsv.lua
Normal file → Executable file
@ -122,7 +122,7 @@ local function createField(inputString, quote, fieldStart, i, doubleQuoteEscape)
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- main function used to parse
|
-- main function used to parse
|
||||||
local function parseString(inputString, inputLength, delimiter, i, headerField, fieldsToKeep)
|
local function parseString(inputString, inputLength, delimiter, i, headerField, fieldsToKeep, rowFunc)
|
||||||
|
|
||||||
-- keep track of my chars!
|
-- keep track of my chars!
|
||||||
local currentChar, nextChar = sbyte(inputString, i), nil
|
local currentChar, nextChar = sbyte(inputString, i), nil
|
||||||
@ -240,11 +240,21 @@ local function parseString(inputString, inputLength, delimiter, i, headerField,
|
|||||||
-- print("fs:", fieldStart)
|
-- print("fs:", fieldStart)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- incrememnt for new line
|
-- check the column count
|
||||||
if fieldNum < initialLineCount then
|
if fieldNum < initialLineCount then
|
||||||
error('ftcsv: too few columns in row ' .. lineNum)
|
error('ftcsv: too few columns in row ' .. lineNum)
|
||||||
end
|
end
|
||||||
lineNum = lineNum + 1
|
|
||||||
|
-- transform the row using the supplied function
|
||||||
|
if rowFunc then
|
||||||
|
outResults[lineNum] = rowFunc(outResults[lineNum], lineNum)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- incrememnt for new line, if row transformation hasn't removed the current row.
|
||||||
|
if outResults[lineNum] then
|
||||||
|
lineNum = lineNum + 1
|
||||||
|
end
|
||||||
|
|
||||||
outResults[lineNum] = {}
|
outResults[lineNum] = {}
|
||||||
fieldNum = 1
|
fieldNum = 1
|
||||||
fieldStart = i + 1 + skipChar
|
fieldStart = i + 1 + skipChar
|
||||||
@ -284,6 +294,10 @@ local function parseString(inputString, inputLength, delimiter, i, headerField,
|
|||||||
-- otherwise there might not be enough line
|
-- otherwise there might not be enough line
|
||||||
elseif finalLineCount < initialLineCount then
|
elseif finalLineCount < initialLineCount then
|
||||||
error('ftcsv: too few columns in row ' .. lineNum)
|
error('ftcsv: too few columns in row ' .. lineNum)
|
||||||
|
|
||||||
|
-- else it is a fully-formed line, so do row transformation if required.
|
||||||
|
elseif rowFunc then
|
||||||
|
outResults[lineNum] = rowFunc(outResults[lineNum], lineNum)
|
||||||
end
|
end
|
||||||
|
|
||||||
return outResults
|
return outResults
|
||||||
@ -300,6 +314,7 @@ function ftcsv.parse(inputFile, delimiter, options)
|
|||||||
local fieldsToKeep = nil
|
local fieldsToKeep = nil
|
||||||
local loadFromString = false
|
local loadFromString = false
|
||||||
local headerFunc
|
local headerFunc
|
||||||
|
local rowFunc
|
||||||
if options then
|
if options then
|
||||||
if options.headers ~= nil then
|
if options.headers ~= nil then
|
||||||
assert(type(options.headers) == "boolean", "ftcsv only takes the boolean 'true' or 'false' for the optional parameter 'headers' (default 'true'). You passed in '" .. tostring(options.headers) .. "' of type '" .. type(options.headers) .. "'.")
|
assert(type(options.headers) == "boolean", "ftcsv only takes the boolean 'true' or 'false' for the optional parameter 'headers' (default 'true'). You passed in '" .. tostring(options.headers) .. "' of type '" .. type(options.headers) .. "'.")
|
||||||
@ -330,6 +345,10 @@ function ftcsv.parse(inputFile, delimiter, options)
|
|||||||
assert(type(options.headerFunc) == "function", "ftcsv only takes a function value for optional parameter 'headerFunc'. You passed in '" .. tostring(options.headerFunc) .. "' of type '" .. type(options.headerFunc) .. "'.")
|
assert(type(options.headerFunc) == "function", "ftcsv only takes a function value for optional parameter 'headerFunc'. You passed in '" .. tostring(options.headerFunc) .. "' of type '" .. type(options.headerFunc) .. "'.")
|
||||||
headerFunc = options.headerFunc
|
headerFunc = options.headerFunc
|
||||||
end
|
end
|
||||||
|
if options.rowFunc ~= nil then
|
||||||
|
assert(type(options.rowFunc) == "function", "ftcsv only takes a function value for optional parameter 'rowFunc'. You passed in '" .. tostring(options.rowFunc) .. "' of type '" .. type(options.rowFunc) .. "'.")
|
||||||
|
rowFunc = options.rowFunc
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- handle input via string or file!
|
-- handle input via string or file!
|
||||||
@ -389,7 +408,7 @@ function ftcsv.parse(inputFile, delimiter, options)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local output = parseString(inputString, inputLength, delimiter, i, headerField, fieldsToKeep)
|
local output = parseString(inputString, inputLength, delimiter, i, headerField, fieldsToKeep, rowFunc)
|
||||||
return output
|
return output
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -158,6 +158,19 @@ describe("csv features", function()
|
|||||||
assert.are.same(expected, actual)
|
assert.are.same(expected, actual)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
it("should make column A uppercase via rowFunc", function()
|
||||||
|
local expected = {}
|
||||||
|
expected[1] = {}
|
||||||
|
expected[1].a = "APPLE"
|
||||||
|
expected[1].b = "banana"
|
||||||
|
expected[1].c = "carrot"
|
||||||
|
local actual = ftcsv.parse("a,b,c\napple,banana,carrot", ",", {loadFromString=true, rowFunc=function(row)
|
||||||
|
row.a = string.upper(row.a)
|
||||||
|
return row
|
||||||
|
end})
|
||||||
|
assert.are.same(expected, actual)
|
||||||
|
end)
|
||||||
|
|
||||||
it("should handle encoding files", function()
|
it("should handle encoding files", function()
|
||||||
local expected = {}
|
local expected = {}
|
||||||
expected[1] = {}
|
expected[1] = {}
|
||||||
@ -191,4 +204,4 @@ describe("csv features", function()
|
|||||||
assert.are.same(expected, actual)
|
assert.are.same(expected, actual)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
end)
|
end)
|
||||||
|
Loading…
Reference in New Issue
Block a user