...
1
2
3
4
5 package csv
6
7 import (
8 "bufio"
9 "io"
10 "strings"
11 "unicode"
12 "unicode/utf8"
13 )
14
15
16
17
18
19
20
21
22
23
24 type Writer struct {
25 Comma rune
26 UseCRLF bool
27 w *bufio.Writer
28 }
29
30
31 func NewWriter(w io.Writer) *Writer {
32 return &Writer{
33 Comma: ',',
34 w: bufio.NewWriter(w),
35 }
36 }
37
38
39
40 func (w *Writer) Write(record []string) error {
41 if !validDelim(w.Comma) {
42 return errInvalidDelim
43 }
44
45 for n, field := range record {
46 if n > 0 {
47 if _, err := w.w.WriteRune(w.Comma); err != nil {
48 return err
49 }
50 }
51
52
53
54 if !w.fieldNeedsQuotes(field) {
55 if _, err := w.w.WriteString(field); err != nil {
56 return err
57 }
58 continue
59 }
60 if err := w.w.WriteByte('"'); err != nil {
61 return err
62 }
63
64 for _, r1 := range field {
65 var err error
66 switch r1 {
67 case '"':
68 _, err = w.w.WriteString(`""`)
69 case '\r':
70 if !w.UseCRLF {
71 err = w.w.WriteByte('\r')
72 }
73 case '\n':
74 if w.UseCRLF {
75 _, err = w.w.WriteString("\r\n")
76 } else {
77 err = w.w.WriteByte('\n')
78 }
79 default:
80 _, err = w.w.WriteRune(r1)
81 }
82 if err != nil {
83 return err
84 }
85 }
86
87 if err := w.w.WriteByte('"'); err != nil {
88 return err
89 }
90 }
91 var err error
92 if w.UseCRLF {
93 _, err = w.w.WriteString("\r\n")
94 } else {
95 err = w.w.WriteByte('\n')
96 }
97 return err
98 }
99
100
101
102 func (w *Writer) Flush() {
103 w.w.Flush()
104 }
105
106
107 func (w *Writer) Error() error {
108 _, err := w.w.Write(nil)
109 return err
110 }
111
112
113 func (w *Writer) WriteAll(records [][]string) error {
114 for _, record := range records {
115 err := w.Write(record)
116 if err != nil {
117 return err
118 }
119 }
120 return w.w.Flush()
121 }
122
123
124
125
126
127
128
129
130
131
132
133
134
135 func (w *Writer) fieldNeedsQuotes(field string) bool {
136 if field == "" {
137 return false
138 }
139 if field == `\.` || strings.ContainsRune(field, w.Comma) || strings.ContainsAny(field, "\"\r\n") {
140 return true
141 }
142
143 r1, _ := utf8.DecodeRuneInString(field)
144 return unicode.IsSpace(r1)
145 }
146
View as plain text