Skip to content

Instantly share code, notes, and snippets.

@eborden
Created October 7, 2016 21:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save eborden/4c9519dedecb93f5789b9c0fba437d5e to your computer and use it in GitHub Desktop.
Save eborden/4c9519dedecb93f5789b9c0fba437d5e to your computer and use it in GitHub Desktop.
Naive CSV parser in Elixir
defmodule CSV do
defp linesTransform(str, acc) do
case String.split(str, ~r/\n|\r\n/) do
[] -> {:halt, acc}
[head] -> {[], acc <> head}
[head | tail] ->
interspersedLines = Enum.take(tail, Enum.count(tail) - 1)
{[acc <> head] ++ interspersedLines, List.last tail}
end
end
defp lines(enum) do
Stream.transform(enum, "", &linesTransform(&1, &2))
end
defp split(enum, delim) do
Stream.map(enum, &String.split(&1, delim))
end
def parse(enum, args) do
delimiter = Keyword.get(args, :delimiter, ",")
with_head = Keyword.get(args, :with_head, false)
lined = lines(enum)
if with_head do
headers = Stream.take(lined, 1)
|> split(delimiter)
|> Stream.concat
|> Enum.map(&String.to_atom &1)
lined |> Stream.drop(1)
|> split(delimiter)
|> Stream.map(&List.zip([headers, &1]))
|> Stream.map(&Enum.into(&1, %{}))
else
lined |> split(delimiter)
end
end
end
IO.puts "With Header Parsing"
File.stream!("foo.csv", [:utf8], 1024)
|> CSV.parse(delimiter: ",", with_head: true)
|> Stream.take(1)
|> Enum.each(&IO.puts(&1[:Email]))
IO.puts ""
IO.puts "Without Header Parsing"
File.stream!("foo.csv", [:utf8], 1024)
|> CSV.parse(delimiter: ",")
|> Stream.take(2)
|> Enum.each(&Enum.at(&1, 1) |> IO.puts)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment