csv_tools.anubis 3.33 KB
/*
 * Created by PyramIDE.
 * User: フランスのトトロ aka (David RENÉ) 
 * Date: 06/05/2017
 * Time: 17:33
 * © Calexium 
 */

read tools/basis.anubis
read system/string.anubis
read system/data_io.anubis
read tools/line_reader.anubis

public define (List(String), Bool, List(Word8))
  csv_split_by_tokens
  (
    List(Word8)   line,         // list of left char to parse in the line
    List(Word8)   tokens,       // list of tokens as separator
    List(Word8)   current,      // current column chars
    List(String)  so_far,       // list of already parsed column
    Bool          inside_string // flag which indicate we are inside string 
  ) =
  if line is
  {
    []  then 
      if length(current) > 0 then
        if inside_string then 
          (reverse(so_far), inside_string, current)
        else
          (reverse([ implode(reverse(current)) . so_far]), false, [])
      else
        (reverse(so_far), inside_string, []),
        
    [ char . t ] then
      if char = '\"' then
        with double_delimiter = if t is 
                                {
                                  [] then false,
                                  [char2 . t2] then char2 = char
                                },
        if inside_string then
          if double_delimiter then
            csv_split_by_tokens(if t is [_ . t2] then t2 else [], tokens, [ char . current ], so_far, inside_string)
          else 
            csv_split_by_tokens(t, tokens, current, so_far, false)  // end of string
        else
          csv_split_by_tokens(t, tokens, current, so_far, true)     // start of string
          
      else if member(tokens, char) & inside_string = false then
        csv_split_by_tokens( t, tokens, [], [ trim(implode(reverse(current))) . so_far], false)
        
      else
        csv_split_by_tokens( t, tokens, [ char . current ], so_far, inside_string)
  }.

public define (List(String), Bool, List(Word8))
  csv_split_by_tokens
  (
    String      line,
    List(Word8) tokens,
    Bool          inside_string
  )=
  csv_split_by_tokens(explode(line), tokens, [], [], inside_string).

/**
 * Splits a line using token as separator, taking care of '"' as string delimiter. 
 * So all tokens found between two delimiter will be ignored.
 * Return the list of elements and a boolean set to true if the EOL was found inside a string.
 */
public define (List(String), Bool, List(Word8))
  csv_split
  (
    String  line,
    Word8   token,
    Bool    inside_string
  )=
  csv_split_by_tokens(explode(line), [token], [], [], inside_string).

public define Maybe((String, List(String)))
  csv_read_line
  (
    Data_IO       io,
    Word8         separator,
    Bool          inside_string,
    String        full_line,
    List(Word8)   current_column,
    List(String)  so_far
  ) =
  if (Maybe(String))read_line(io) is
  {
    failure then 
      if length(full_line) > 0 then 
        println("quitting csv_read_line (read_line failure)"); 
        success((full_line, so_far))
      else 
        failure,
    success(line) then
  
      if csv_split_by_tokens(explode(line), [separator], current_column, [], inside_string) is (all_values, should_continue, partial) then
      if should_continue then
        csv_read_line(io, separator, true, full_line + line + "\n", partial, so_far + all_values)
      else
        success((full_line + line, so_far + all_values))
  }.