Skip to content

Commit

Permalink
fix #157: split function accounting for quotes
Browse files Browse the repository at this point in the history
Added Util.splitCSVLine() function that splits a CSV-formatted string into an array of tokens, accounting for quotes (single and double) and escape characters.
  • Loading branch information
mikyll committed Jul 6, 2024
1 parent 24bd8d6 commit 27d178d
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 1 deletion.
2 changes: 1 addition & 1 deletion src/persist/Adapter.lua
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ function Adapter.loadPolicyLine(line, model)
return
end

local tokens = Util.split(line, ",")
local tokens = Util.splitCSVLine(line)
local key = tokens[1]
local sec = key:sub(1, 1)

Expand Down
62 changes: 62 additions & 0 deletions src/util/Util.lua
Original file line number Diff line number Diff line change
Expand Up @@ -252,4 +252,66 @@ function Util.printTable(t)
return s
end

function Util.splitCSVLine(line, sep, trimFields)
local result = {}
local i = 1
local inQuotes = false
local quoteChar = nil
local escaping = false
local field = ""

if sep == nil then sep = ',' end
if trimFields == nil then trimFields = true end

-- Loop over the characters of the line
while i <= #line do
local char = line:sub(i, i)

-- Check if we found the escape character and are not inside single quotes
if char == '\\' and quoteChar ~= '\'' then
-- The next character will be escaped (added directly to the token)
escaping = true
else
if escaping then
field = field .. char
escaping = false
else
-- Check if we are already inside quotes
if inQuotes then
-- Check if we can close quoted text
if char == quoteChar then
inQuotes = false
quoteChar = nil
else
field = field .. char
end
else -- not in quotes
if char == '"' or char == '\'' then
inQuotes = true
quoteChar = char
elseif char == ',' then
if trimFields then
field = Util.trim(field)
end

table.insert(result, field)
field = ""
else
field = field .. char
end
end
end
end
i = i + 1
end

-- Add the last field (since it won't have the delimiter after it)
if trimFields then
field = Util.trim(field)
end
table.insert(result, field)

return result
end

return Util

0 comments on commit 27d178d

Please sign in to comment.