encoding.csv: add write support
parent
56566ba3d0
commit
1ba701e036
|
@ -1,9 +1,9 @@
|
||||||
module csv
|
|
||||||
|
|
||||||
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
|
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
|
||||||
// Use of this source code is governed by an MIT license
|
// Use of this source code is governed by an MIT license
|
||||||
// that can be found in the LICENSE file.
|
// that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
module csv
|
||||||
|
|
||||||
// Once interfaces are further along the idea would be to have something similar to
|
// Once interfaces are further along the idea would be to have something similar to
|
||||||
// go's io.reader & bufio.reader rather than reading the whole file into string, this
|
// go's io.reader & bufio.reader rather than reading the whole file into string, this
|
||||||
// would then satisfy that interface. I designed it this way to be easily adapted.
|
// would then satisfy that interface. I designed it this way to be easily adapted.
|
||||||
|
@ -21,6 +21,7 @@ struct Reader {
|
||||||
// has_header bool
|
// has_header bool
|
||||||
// headings []string
|
// headings []string
|
||||||
data string
|
data string
|
||||||
|
pub:
|
||||||
mut:
|
mut:
|
||||||
delimiter byte
|
delimiter byte
|
||||||
comment byte
|
comment byte
|
||||||
|
@ -92,6 +93,9 @@ fn (r mut Reader) read_record() ?[]string {
|
||||||
if r.delimiter == r.comment {
|
if r.delimiter == r.comment {
|
||||||
return err_comment_is_delim
|
return err_comment_is_delim
|
||||||
}
|
}
|
||||||
|
if !valid_delim(r.delimiter) {
|
||||||
|
return err_invalid_delim
|
||||||
|
}
|
||||||
mut line := ''
|
mut line := ''
|
||||||
for {
|
for {
|
||||||
l := r.read_line() or {
|
l := r.read_line() or {
|
||||||
|
@ -122,16 +126,18 @@ fn (r mut Reader) read_record() ?[]string {
|
||||||
else {
|
else {
|
||||||
line = line.right(1)
|
line = line.right(1)
|
||||||
i = line.index('"')
|
i = line.index('"')
|
||||||
if i+1 == line.len {
|
if i != -1 {
|
||||||
// last record
|
if i+1 == line.len {
|
||||||
fields << line.left(i)
|
// last record
|
||||||
break
|
fields << line.left(i)
|
||||||
}
|
break
|
||||||
next := line[i+1]
|
}
|
||||||
if next == r.delimiter {
|
next := line[i+1]
|
||||||
fields << line.left(i)
|
if next == r.delimiter {
|
||||||
line = line.right(i)
|
fields << line.left(i)
|
||||||
continue
|
line = line.right(i)
|
||||||
|
continue
|
||||||
|
}
|
||||||
}
|
}
|
||||||
line = line.right(1)
|
line = line.right(1)
|
||||||
}
|
}
|
||||||
|
@ -142,3 +148,10 @@ fn (r mut Reader) read_record() ?[]string {
|
||||||
|
|
||||||
return fields
|
return fields
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn valid_delim(b byte) bool {
|
||||||
|
return b != 0 &&
|
||||||
|
b != `"` &&
|
||||||
|
b != `\r` &&
|
||||||
|
b != `\n`
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,89 @@
|
||||||
|
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
|
||||||
|
// Use of this source code is governed by an MIT license
|
||||||
|
// that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
module csv
|
||||||
|
|
||||||
|
import strings
|
||||||
|
|
||||||
|
struct Writer {
|
||||||
|
sb strings.Builder
|
||||||
|
pub:
|
||||||
|
mut:
|
||||||
|
use_crlf bool
|
||||||
|
delimiter byte
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_writer() *Writer {
|
||||||
|
return &Writer{
|
||||||
|
delimiter: `,`,
|
||||||
|
sb: strings.new_builder(200)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// write writes a single record
|
||||||
|
pub fn (w mut Writer) write(record []string) ?bool {
|
||||||
|
if !valid_delim(w.delimiter) {
|
||||||
|
return err_invalid_delim
|
||||||
|
}
|
||||||
|
le := if w.use_crlf { '\r\n' } else { '\n' }
|
||||||
|
for n, _field in record {
|
||||||
|
mut field := _field
|
||||||
|
if n > 0 {
|
||||||
|
w.sb.write(w.delimiter.str())
|
||||||
|
}
|
||||||
|
|
||||||
|
if !w.field_needs_quotes(field) {
|
||||||
|
w.sb.write(field)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
w.sb.write('"')
|
||||||
|
|
||||||
|
for field.len > 0 {
|
||||||
|
mut i := field.index_any('"\r\n')
|
||||||
|
if i < 0 {
|
||||||
|
i = field.len
|
||||||
|
}
|
||||||
|
|
||||||
|
w.sb.write(field.left(i))
|
||||||
|
field = field.right(i)
|
||||||
|
|
||||||
|
if field.len > 0 {
|
||||||
|
z := field[0]
|
||||||
|
switch z {
|
||||||
|
case `"`:
|
||||||
|
w.sb.write('""')
|
||||||
|
case `\r` || `\n`:
|
||||||
|
w.sb.write(le)
|
||||||
|
}
|
||||||
|
field = field.right(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
w.sb.write('"')
|
||||||
|
}
|
||||||
|
|
||||||
|
w.sb.write(le)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Once we have multi dimensional array
|
||||||
|
// pub fn (w &Writer) write_all(records [][]string) {
|
||||||
|
// for _, record in records {
|
||||||
|
// w.write(record)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
fn (w &Writer) field_needs_quotes(field string) bool {
|
||||||
|
if field == '' {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if field.contains(w.delimiter.str()) || (field.index_any('"\r\n') != -1) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (w &Writer) str() string {
|
||||||
|
return w.sb.str()
|
||||||
|
}
|
Loading…
Reference in New Issue