Skip to content

Commit

Permalink
added updated parser_to_h and added test cases
Browse files Browse the repository at this point in the history
  • Loading branch information
Zeljko-Predjeskovic committed Dec 9, 2024
1 parent ff5ed33 commit 6ef3352
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 11 deletions.
31 changes: 27 additions & 4 deletions spec/std/csv/csv_parse_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -50,16 +50,39 @@ describe CSV do
end

it "parses to hashes" do
csv_text = "Index,Customer Id,First Name,Last Name
1,DD37Cf93aecA6Dc,Sheryl,Baxter
2,1Ef7b82A4CAAD10,Preston,Lozano
3,6F94879bDAfE5a6,,Berry"
csv_text = "Index,Customer Id,First Name,Last Name\n\n1,DD37Cf93aecA6Dc,Sheryl,Baxter\n2,1Ef7b82A4CAAD10,Preston,Lozano\n3,6F94879bDAfE5a6,,Berry, Jerry, \n"

CSV.parse_to_h(csv_text).should eq([{"Index" => "1", "Customer Id" => "DD37Cf93aecA6Dc", "First Name" => "Sheryl", "Last Name" => "Baxter"},
{"Index" => "2", "Customer Id" => "1Ef7b82A4CAAD10", "First Name" => "Preston", "Last Name" => "Lozano"},
{"Index" => "3", "Customer Id" => "6F94879bDAfE5a6", "First Name" => "", "Last Name" => "Berry"}])
end

it "parses to hashes with no headers" do
csv_text = "\n1,DD37Cf93aecA6Dc,Sheryl,Baxter\n2,1Ef7b82A4CAAD10,Preston,Lozano\n3,6F94879bDAfE5a6,,Berry"

actual = [{} of String => String, {} of String => String, {} of String => String]

CSV.parse_to_h(csv_text).should eq(actual)
end

it "parses to hashes with only headers" do
csv_text = "Index,Customer Id,First Name,Last Name"

CSV.parse_to_h(csv_text).should eq([] of Hash(String, String))
end

it "parses to hashes remaining rows" do
csv_text = "Index,Customer Id,First Name,Last Name\n1,DD37Cf93aecA6Dc,Sheryl,Baxter\n2,1Ef7b82A4CAAD10,Preston,Lozano\n3,6F94879bDAfE5a6,,Berry"
parser = CSV::Parser.new(csv_text)
# skip header
parser.next_row
# skip rows
parser.next_row
parser.next_row

parser.parse_to_h.should eq([{"Index" => "3", "Customer Id" => "6F94879bDAfE5a6", "First Name" => "", "Last Name" => "Berry"}])
end

it "raises if single quote in the middle" do
expect_raises CSV::MalformedCSVError, "Unexpected quote at line 1, column 4" do
CSV.parse(%(hel"lo))
Expand Down
3 changes: 3 additions & 0 deletions src/csv/lexer.cr
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ abstract class CSV::Lexer
getter separator : Char
getter quote_char : Char

# :nodoc:
protected getter line_number : Int32

# :nodoc:
def initialize(@separator : Char = DEFAULT_SEPARATOR, @quote_char : Char = DEFAULT_QUOTE_CHAR)
@token = Token.new
Expand Down
20 changes: 13 additions & 7 deletions src/csv/parser.cr
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,17 @@ class CSV::Parser

def parse_to_h : Array(Hash(String, String))
rows = [] of Hash(String, String)
row_number = @lexer.line_number

rewind
if headers = next_row
while row = next_row
rows << parse_row_to_h_internal(headers, row)
while @lexer.line_number < row_number
next_row
end
each_row do |row|
if parsed_row = parse_row_to_h_internal(headers, row)
rows << parsed_row
end
end
end
rows
Expand Down Expand Up @@ -81,12 +89,10 @@ class CSV::Parser
end
end

private def parse_row_to_h_internal(headers : Array(String), row : Array(String)) : Hash(String, String)
private def parse_row_to_h_internal(headers : Array(String), row : Array(String)) : Hash(String, String) | Nil
h = {} of String => String
headers.each_with_index do |header, i|
h[header] = row[i].strip || ""
end
h
row.empty? ? return nil : headers.each_with_index { |header, i| h[header] = row[i] }
return h
end

private struct RowIterator
Expand Down

0 comments on commit 6ef3352

Please sign in to comment.