1 package com.opencsv;
2
3 import com.opencsv.enums.CSVReaderNullFieldIndicator;
4 import org.apache.commons.lang3.StringUtils;
5
6 import java.io.IOException;
7 import java.util.regex.Pattern;
8 import java.util.stream.Collectors;
9 import java.util.stream.Stream;
10
11
12
13
14
15 public abstract class AbstractCSVParser implements ICSVParser {
16
17
18
19 protected static final Pattern SPECIAL_REGEX_CHARS = Pattern.compile("[{}()\\[\\].+*?^$\\\\|]");
20
21
22
23
24 protected static final StringBuilder EMPTY_STRINGBUILDER = new StringBuilder("");
25
26
27
28
29 protected final char separator;
30
31
32
33 protected final String separatorAsString;
34
35
36
37 protected final char quotechar;
38
39
40
41 protected final String quotecharAsString;
42
43
44
45
46 protected final String quoteDoubledAsString;
47
48
49
50
51 protected final Pattern quoteMatcherPattern;
52
53
54
55
56
57
58
59 protected final CSVReaderNullFieldIndicator nullFieldIndicator;
60
61
62
63
64 protected String pending;
65
66
67
68
69
70
71
72
73 public AbstractCSVParser(char separator, char quotechar, CSVReaderNullFieldIndicator nullFieldIndicator) {
74 this.separator = separator;
75 this.separatorAsString = SPECIAL_REGEX_CHARS.matcher(Character.toString(separator)).replaceAll("\\\\$0");
76
77 this.quotechar = quotechar;
78 this.quotecharAsString = Character.toString(quotechar);
79 this.quoteDoubledAsString = this.quotecharAsString + this.quotecharAsString;
80 this.quoteMatcherPattern = Pattern.compile(quotecharAsString);
81
82 this.nullFieldIndicator = nullFieldIndicator;
83 }
84
85 @Override
86 public char getSeparator() {
87 return separator;
88 }
89
90
91
92
93 public String getSeparatorAsString() {
94 return separatorAsString;
95 }
96
97 @Override
98 public char getQuotechar() {
99 return quotechar;
100 }
101
102
103
104
105 public String getQuotecharAsString() {
106 return quotecharAsString;
107 }
108
109 @Override
110 public boolean isPending() {
111 return pending != null;
112 }
113
114
115 @Override
116 public String[] parseLineMulti(String nextLine) throws IOException {
117 return parseLine(nextLine, true);
118 }
119
120 @Override
121 public String[] parseLine(String nextLine) throws IOException {
122 return parseLine(nextLine, false);
123 }
124
125 @Override
126 public String parseToLine(String[] values, boolean applyQuotesToAll) {
127 return Stream.of(values)
128 .map(v -> convertToCsvValue(v, applyQuotesToAll))
129 .collect(Collectors.joining(getSeparatorAsString()));
130 }
131
132 @Override
133 public void parseToLine(String[] values, boolean applyQuotesToAll, Appendable appendable) throws IOException {
134 boolean first = true;
135 for (String value : values) {
136 if (!first) {
137 appendable.append(getSeparator());
138 } else {
139 first = false;
140 }
141 convertToCsvValue(value, applyQuotesToAll, appendable);
142 }
143 }
144
145
146
147
148
149
150
151
152
153 protected abstract String convertToCsvValue(String value, boolean applyQuotestoAll);
154
155
156
157
158
159
160
161
162
163
164
165
166 protected void convertToCsvValue(String value, boolean applyQuotesToAll, Appendable appendable) throws IOException {
167 appendable.append(convertToCsvValue(value, applyQuotesToAll));
168 }
169
170
171
172
173
174
175
176
177 protected boolean isSurroundWithQuotes(String value, boolean forceSurround) {
178 if (value == null) {
179 return nullFieldIndicator.equals(CSVReaderNullFieldIndicator.EMPTY_QUOTES);
180 } else if (value.isEmpty() && nullFieldIndicator.equals(CSVReaderNullFieldIndicator.EMPTY_SEPARATORS)) {
181 return true;
182 }
183
184 return forceSurround || value.contains(getSeparatorAsString()) || value.contains(NEWLINE);
185 }
186
187
188
189
190
191
192
193
194
195 protected abstract String[] parseLine(String nextLine, boolean multi) throws IOException;
196
197 @Override
198 public CSVReaderNullFieldIndicator nullFieldIndicator() {
199 return nullFieldIndicator;
200 }
201
202 @Override
203 public String getPendingText() {
204 return StringUtils.defaultString(pending);
205 }
206 }