small medium large xlarge

Dave_gnome_head_isolated_pragsmall
15 Jul 2013, 03:42
Dave Thomas (366 posts)
  • The function String.to_float converts a string to either a float or an integer, returning :error if the string was not a valid number.

    Update your CSV sigil so that numbers are automatically converted:

    csv = %c"""
    1,2,3.14
    cat,dog
    """
    

    Would generate [[1,2,3.14], ["cat","dog"]]

Generic-user-small
28 Jan 2015, 21:14
Pierre Sugar (57 posts)
defmodule CsvSigil do

  def sigil_v(lines, _opts) do
    lines
    |> String.rstrip
    |> String.split("\n")
    |> Enum.reduce([], fn l, acc -> acc ++ [to_csv(l)] end)
  end

  def to_csv(values) do
    values 
    |> String.split(",") 
    |> Enum.reduce([], fn v, acc -> [parse(v) | acc] end)
    |> Enum.reverse
  end

  def parse(string), do: _parse(Float.parse(string), string)
  defp _parse({number, rest}, _string) when rest == "", do: number
  defp _parse(             _,  string)                , do: string
end

defmodule Example do
  import CsvSigil

  def lines do
    ~v"""
    1,2,3
    1,2,III
    a,b,c
    x,y,z
    """
  end
end

Results in

iex(146)> Example.lines                      
[[1.0, 2.0, 3.0], [1.0, 2.0, "III"], ["a", "b", "c"], ["x", "y", "z"]] 
Generic-user-small
31 Mar 2016, 11:00
Stefan Houtzager (8 posts)
defmodule LineSigil do
  def sigil_v(lines, _opts), do:
    lines 
    |> String.rstrip 
    |> String.split("\n") 
    |> Enum.map(fn x -> x |> String.split(",") end) 
    |> Enum.map(fn col -> processCollection(col) end)

  defp processCollection(col), do:
    col |> Enum.map(fn element ->
                      case Float.parse(element) do
                        {float, _} -> float
                        _          -> element
                      end
                    end)
end

defmodule Example do
  import LineSigil
  def lines do
    ~v"""
    1,2,3.14
    cat,dog
    """
  end
end

IO.inspect Example.lines
#This produces [[1.0, 2.0, 3.14], ["cat", "dog"]]

Generic-user-small
29 May 2017, 14:57
Matthew Fehskens (11 posts)

Steps are:

  1. Strip the line to remove the trailing newline
  2. Split on newline characters
  3. Loop through lines & split to columns
  4. Replace column values with trimmed versions, converting to floats where appropriate
defmodule CsvSigil do
  def sigil_v(doc, _opts) do
    doc |> String.rstrip()
      |> String.split("\n")
      |> do_replace_text()
  end

  defp do_replace_text(lines) do
    lines |> Enum.map(fn line ->
      line |> do_split_line()
        |> Enum.map(&do_replace_value/1)
    end)
  end

  defp do_split_line(text) do
    text |> String.trim()
      |> String.split(",")
  end

  defp do_replace_value(value) do
    value |> String.trim()
      |> do_number_parse()
  end

  defp do_number_parse(value) do
    case Float.parse(value) do
      :error -> value
      { number, _ } -> number
    end
  end

  defmacro __using__(_opts) do
    quote do
      import unquote(__MODULE__), only: [ sigil_v: 2 ]
    end
  end
end

defmodule Example do
  use CsvSigil

  def run do
    ~v"""
    a,b,c
    1,2.45 ,3
    foo,bar , baz
    """
  end
end

IO.inspect Example.run()

Output:

[["a", "b", "c"], [1.0, 2.45, 3.0], ["foo", "bar", "baz"]]
Generic-user-small
29 May 2017, 15:00
Matthew Fehskens (11 posts)

Steps are:

  1. Strip the line to remove the trailing newline
  2. Split on newline characters
  3. Loop through lines & split to columns
  4. Replace column values with trimmed versions, converting to floats where appropriate
defmodule CsvSigil do
  def sigil_v(doc, _opts) do
    doc |> String.rstrip()
      |> String.split("\n")
      |> do_replace_text()
  end

  defp do_replace_text(lines) do
    lines |> Enum.map(fn line ->
      line |> do_split_line()
        |> Enum.map(&do_replace_value/1)
    end)
  end

  defp do_split_line(text) do
    text |> String.trim()
      |> String.split(",")
  end

  defp do_replace_value(value) do
    value |> String.trim()
      |> do_number_parse()
  end

  defp do_number_parse(value) do
    case Float.parse(value) do
      :error -> value
      { number, _ } -> number
    end
  end

  defmacro __using__(_opts) do
    quote do
      import unquote(__MODULE__), only: [ sigil_v: 2 ]
    end
  end
end

defmodule Example do
  use CsvSigil

  def run do
    ~v"""
    a,b,c
    1,2.45 ,3
    foo,bar , baz
    """
  end
end

IO.inspect Example.run()

Output:

[["a", "b", "c"], [1.0, 2.45, 3.0], ["foo", "bar", "baz"]]
You must be logged in to comment