package csvparser import ( "strings" ) type EncloserId int const ( DoubleQuotes EncloserId = iota SingleQuotes RoundBrackets SquareBrackets CurlyBrackets ) type Encloser struct { Open rune Close rune } var EnclosersRunes = map[EncloserId]Encloser{ DoubleQuotes: Encloser{'"', '"'}, SingleQuotes: Encloser{'\'', '\''}, RoundBrackets: Encloser{'(', ')'}, SquareBrackets: Encloser{'[', ']'}, CurlyBrackets: Encloser{'{', '}'}, } type CsvParser struct { Enclosers []EncloserId Delimiter rune DelimiterString string } func (parser *CsvParser) Init() { parser.Enclosers = []EncloserId{DoubleQuotes, SquareBrackets} parser.Delimiter = ' ' parser.DelimiterString = string(parser.Delimiter) } func (parser *CsvParser) Parse(line string) error { for len(line) > 0 { line = strings.TrimLeft(line, parser.DelimiterString) line = strings.TrimRight(line, parser.DelimiterString) if len(line) == 0 { break } // Search for an encloser for id := range parser.Enclosers { if line[0] == EnclosersRunes[id].Open { endChar := EnclosersRunes[id].Close endOfFieldFound := false l := len(line) for i := 1; i < l; i++ { if line[i] == endChar && line[i-1] != '\\' { fields = append(fields, line[1:i]) line = line[i+1:] endOfFieldFound = true break } } if !endOfFieldFound { return nil, errors.New("#ERR: bad format") } break; } } if line[0] == '"' || line[0] == '[' { var endChar byte = '"' if line[0] == '[' { endChar = ']' } endOfFieldFound := false l := len(line) for i := 1; i < l; i++ { if line[i] == endChar && line[i-1] != '\\' { fields = append(fields, line[1:i]) line = line[i+1:] endOfFieldFound = true break } } if !endOfFieldFound { return nil, errors.New("#ERR: bad format") } } else { nextSpace := strings.IndexAny(line, " \t") if nextSpace != -1 { fields = append(fields, line[:nextSpace]) line = line[nextSpace:] } else { fields = append(fields, line) line = "" break } } } return fields, nil }