1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 package org.apache.commons.csv;
19
20 import static org.apache.commons.csv.Constants.COMMA;
21 import static org.apache.commons.csv.Constants.CR;
22 import static org.apache.commons.csv.Constants.CRLF;
23 import static org.apache.commons.csv.Constants.DOUBLE_QUOTE_CHAR;
24 import static org.apache.commons.csv.Constants.BACKSLASH;
25 import static org.apache.commons.csv.Constants.LF;
26 import static org.apache.commons.csv.Constants.TAB;
27
28 import java.io.IOException;
29 import java.io.Reader;
30 import java.io.Serializable;
31 import java.io.StringWriter;
32 import java.util.Arrays;
33
34 /**
35 * Specifies the format of a CSV file and parses input.
36 * <p>
37 * This class is immutable.
38 * </p>
39 * You can extend a format through a builder. For example, to extend the Excel format with columns header, you write:
40 * </p>
41 * <pre>CSVFormat.EXCEL.toBuilder().withHeader("Col1", "Col2", "Col3").build();</pre>
42 * <p>
43 * You can parse through a format. For example, to parse an Excel file with columns header, you write:
44 * </p>
45 * <pre>Reader in = ...;
46 *CSVFormat.EXCEL.toBuilder().withHeader("Col1", "Col2", "Col3").parse(in);</pre>
47 * <p>
48 *
49 * @version $Id: CSVFormat.java 1461240 2013-03-26 17:48:22Z ggregory $
50 */
51 public class CSVFormat implements Serializable {
52
53 private static final long serialVersionUID = 1L;
54
55 private final char delimiter;
56 private final Character quoteChar;
57 private final Quote quotePolicy;
58 private final Character commentStart;
59 private final Character escape;
60 private final boolean ignoreSurroundingSpaces; // Should leading/trailing spaces be ignored around values?
61 private final boolean ignoreEmptyLines;
62 private final String recordSeparator; // for outputs
63 private final String[] header;
64
65 /**
66 * Comma separated format as defined by <a href="http://tools.ietf.org/html/rfc4180">RFC 4180</a>.
67 * <h3>RFC 4180:</h3>
68 * <ul>
69 * <li>withDelimiter(',')</li>
70 * <li>withQuoteChar('"')</li>
71 * <li>withLineSeparator(CRLF)</li>
72 * </ul>
73 */
74 public static final CSVFormat RFC4180 =
75 newBuilder()
76 .withIgnoreEmptyLines(false)
77 .build();
78
79 /**
80 * Standard comma separated format, as for {@link #RFC4180} but allowing empty lines.
81 * <h3>RFC 4180:</h3>
82 * <ul>
83 * <li>withDelimiter(',')</li>
84 * <li>withQuoteChar('"')</li>
85 * <li>withLineSeparator(CRLF)</li>
86 * </ul>
87 * <h3>Additional:</h3>
88 * <ul>
89 * <li>withIgnoreEmptyLines(true)</li>
90 * </ul>
91 */
92 public static final CSVFormat DEFAULT =
93 newBuilder()
94 .build();
95
96 /**
97 * Excel file format (using a comma as the value delimiter). Note that the actual value delimiter used by Excel is
98 * locale dependent, it might be necessary to customize this format to accommodate to your regional settings.
99 * <p/>
100 * For example for parsing or generating a CSV file on a French system the following format will be used:
101 *
102 * <pre>
103 * CSVFormat fmt = CSVFormat.newBuilder(EXCEL).withDelimiter(';').build();
104 * </pre>
105 * Settings are:
106 * <ul>
107 * <li>withDelimiter(',')</li>
108 * <li>withQuoteChar('"')</li>
109 * <li>withLineSeparator(CRLF)</li>
110 * </ul>
111 * Note: this is currently the same as RFC4180
112 */
113 public static final CSVFormat EXCEL =
114 newBuilder()
115 .withIgnoreEmptyLines(false)
116 .build();
117
118 /** Tab-delimited format, with quote; leading and trailing spaces ignored. */
119 public static final CSVFormat TDF =
120 newBuilder()
121 .withDelimiter(TAB)
122 .withIgnoreSurroundingSpaces(true)
123 .build();
124
125 /**
126 * Default MySQL format used by the <tt>SELECT INTO OUTFILE</tt> and <tt>LOAD DATA INFILE</tt> operations. This is
127 * a tab-delimited format with a LF character as the line separator. Values are not quoted and special characters
128 * are escaped with '\'.
129 *
130 * @see <a href="http://dev.mysql.com/doc/refman/5.1/en/load-data.html">
131 * http://dev.mysql.com/doc/refman/5.1/en/load-data.html</a>
132 */
133 public static final CSVFormat MYSQL =
134 newBuilder()
135 .withDelimiter(TAB)
136 .withQuoteChar(null)
137 .withEscape(BACKSLASH)
138 .withIgnoreEmptyLines(false)
139 .withRecordSeparator(LF)
140 .build();
141
142 /**
143 * Creates a new CSV format builder.
144 *
145 * @param delimiter
146 * the char used for value separation, must not be a line break character
147 * @return a new CSV format builder.
148 * @throws IllegalArgumentException if the delimiter is a line break character
149 */
150 public static CSVFormatBuilder newBuilder(final char delimiter) {
151 return new CSVFormatBuilder(delimiter);
152 }
153
154 /**
155 * Creates a CSVFormatBuilder, using the values of the given CSVFormat.
156 *
157 * @param format
158 * The format to use values from
159 * @return a new CSVFormatBuilder
160 */
161 public static CSVFormatBuilder newBuilder(final CSVFormat format) {
162 return new CSVFormatBuilder(format);
163 }
164
165 /**
166 * Creates a standard comma separated format builder, as for {@link #RFC4180} but allowing empty lines.
167 * <ul>
168 * <li>withDelimiter(',')</li>
169 * <li>withQuoteChar('"')</li>
170 * <li>withEmptyLinesIgnored(true)</li>
171 * <li>withLineSeparator(CRLF)</li>
172 * </ul>
173 *
174 * Shortcut for {@code CSVFormat.newBuilder(CSVFormat.DEFAULT)}
175 *
176 * @return a standard comma separated format builder, as for {@link #RFC4180} but allowing empty lines.
177 */
178 public static CSVFormatBuilder newBuilder() {
179 return new CSVFormatBuilder(COMMA, DOUBLE_QUOTE_CHAR, null, null, null, false, true, CRLF, null);
180 }
181
182 /**
183 * Creates a customized CSV format.
184 *
185 * @param delimiter
186 * the char used for value separation, must not be a line break character
187 * @param quoteChar
188 * the char used as value encapsulation marker
189 * @param quotePolicy
190 * the quote policy
191 * @param commentStart
192 * the char used for comment identification
193 * @param escape
194 * the char used to escape special characters in values
195 * @param ignoreSurroundingSpaces
196 * <tt>true</tt> when whitespaces enclosing values should be ignored
197 * @param ignoreEmptyLines
198 * <tt>true</tt> when the parser should skip empty lines
199 * @param recordSeparator
200 * the line separator to use for output
201 * @param header
202 * the header
203 * @throws IllegalArgumentException if the delimiter is a line break character
204 */
205 // package protected to give access without needing a synthetic accessor
206 CSVFormat(final char delimiter, final Character quoteChar,
207 final Quote quotePolicy, final Character commentStart,
208 final Character escape, final boolean ignoreSurroundingSpaces,
209 final boolean ignoreEmptyLines, final String lineSeparator,
210 final String[] header) {
211 if (isLineBreak(delimiter)) {
212 throw new IllegalArgumentException("The delimiter cannot be a line break");
213 }
214 this.delimiter = delimiter;
215 this.quoteChar = quoteChar;
216 this.quotePolicy = quotePolicy;
217 this.commentStart = commentStart;
218 this.escape = escape;
219 this.ignoreSurroundingSpaces = ignoreSurroundingSpaces;
220 this.ignoreEmptyLines = ignoreEmptyLines;
221 this.recordSeparator = lineSeparator;
222 this.header = header == null ? null : header.clone();
223 }
224
225 /**
226 * Returns true if the given character is a line break character.
227 *
228 * @param c
229 * the character to check
230 *
231 * @return true if <code>c</code> is a line break character
232 */
233 // package protected to give access without needing a synthetic accessor
234 static boolean isLineBreak(final Character c) {
235 return c != null && isLineBreak(c.charValue());
236 }
237
238 /**
239 * Returns true if the given character is a line break character.
240 *
241 * @param c
242 * the character to check
243 *
244 * @return true if <code>c</code> is a line break character
245 */
246 // package protected to give access without needing a synthetic accessor
247 static boolean isLineBreak(final char c) {
248 return c == LF || c == CR;
249 }
250
251 /**
252 * Returns the character delimiting the values (typically ';', ',' or '\t').
253 *
254 * @return the delimiter character
255 */
256 public char getDelimiter() {
257 return delimiter;
258 }
259
260 /**
261 * Returns the character used to encapsulate values containing special characters.
262 *
263 * @return the quoteChar character
264 */
265 public Character getQuoteChar() {
266 return quoteChar;
267 }
268
269 /**
270 * Returns whether an quoteChar has been defined.
271 *
272 * @return {@code true} if an quoteChar is defined
273 */
274 public boolean isQuoting() {
275 return quoteChar != null;
276 }
277
278 /**
279 * Returns the character marking the start of a line comment.
280 *
281 * @return the comment start marker.
282 */
283 public Character getCommentStart() {
284 return commentStart;
285 }
286
287 /**
288 * Specifies whether comments are supported by this format.
289 *
290 * Note that the comment introducer character is only recognised at the start of a line.
291 *
292 * @return <tt>true</tt> is comments are supported, <tt>false</tt> otherwise
293 */
294 public boolean isCommentingEnabled() {
295 return commentStart != null;
296 }
297
298 /**
299 * Returns the escape character.
300 *
301 * @return the escape character
302 */
303 public Character getEscape() {
304 return escape;
305 }
306
307 /**
308 * Returns whether escape are being processed.
309 *
310 * @return {@code true} if escapes are processed
311 */
312 public boolean isEscaping() {
313 return escape != null;
314 }
315
316 /**
317 * Specifies whether spaces around values are ignored when parsing input.
318 *
319 * @return <tt>true</tt> if spaces around values are ignored, <tt>false</tt> if they are treated as part of the
320 * value.
321 */
322 public boolean getIgnoreSurroundingSpaces() {
323 return ignoreSurroundingSpaces;
324 }
325
326 /**
327 * Specifies whether empty lines between records are ignored when parsing input.
328 *
329 * @return <tt>true</tt> if empty lines between records are ignored, <tt>false</tt> if they are turned into empty
330 * records.
331 */
332 public boolean getIgnoreEmptyLines() {
333 return ignoreEmptyLines;
334 }
335
336 /**
337 * Returns the line separator delimiting output records.
338 *
339 * @return the line separator
340 */
341 public String getRecordSeparator() {
342 return recordSeparator;
343 }
344
345 String[] getHeader() {
346 return header;
347 }
348
349 /**
350 * Parses the specified content.
351 *
352 * @param in
353 * the input stream
354 * @return a stream of CSVRecord
355 * @throws IOException
356 * If an I/O error occurs
357 */
358 public Iterable<CSVRecord> parse(final Reader in) throws IOException {
359 return new CSVParser(in, this);
360 }
361
362 /**
363 * Formats the specified values.
364 *
365 * @param values
366 * the values to format
367 * @return the formatted values
368 */
369 public String format(final Object... values) {
370 final StringWriter out = new StringWriter();
371 try {
372 new CSVPrinter(out, this).printRecord(values);
373 return out.toString().trim();
374 } catch (final IOException e) {
375 // should not happen because a StringWriter does not do IO.
376 throw new IllegalStateException(e);
377 }
378 }
379
380 @Override
381 public String toString() {
382 final StringBuilder sb = new StringBuilder();
383 sb.append("Delimiter=<").append(delimiter).append('>');
384 if (isEscaping()) {
385 sb.append(' ');
386 sb.append("Escape=<").append(escape).append('>');
387 }
388 if (isQuoting()) {
389 sb.append(' ');
390 sb.append("QuoteChar=<").append(quoteChar).append('>');
391 }
392 if (isCommentingEnabled()) {
393 sb.append(' ');
394 sb.append("CommentStart=<").append(commentStart).append('>');
395 }
396 if (getIgnoreEmptyLines()) {
397 sb.append(" EmptyLines:ignored");
398 }
399 if (getIgnoreSurroundingSpaces()) {
400 sb.append(" SurroundingSpaces:ignored");
401 }
402 return sb.toString();
403 }
404
405 /**
406 * Returns the quote policy output fields.
407 *
408 * @return the quote policy
409 */
410 public Quote getQuotePolicy() {
411 return quotePolicy;
412 }
413
414 @Override
415 public int hashCode()
416 {
417 final int prime = 31;
418 int result = 1;
419
420 result = prime * result + delimiter;
421 result = prime * result + ((quotePolicy == null) ? 0 : quotePolicy.hashCode());
422 result = prime * result + ((quoteChar == null) ? 0 : quoteChar.hashCode());
423 result = prime * result + ((commentStart == null) ? 0 : commentStart.hashCode());
424 result = prime * result + ((escape == null) ? 0 : escape.hashCode());
425 result = prime * result + (ignoreSurroundingSpaces ? 1231 : 1237);
426 result = prime * result + (ignoreEmptyLines ? 1231 : 1237);
427 result = prime * result + ((recordSeparator == null) ? 0 : recordSeparator.hashCode());
428 result = prime * result + Arrays.hashCode(header);
429 return result;
430 }
431
432 @Override
433 public boolean equals(final Object obj) {
434 if (this == obj) {
435 return true;
436 }
437 if (obj == null) {
438 return false;
439 }
440 if (getClass() != obj.getClass()) {
441 return false;
442 }
443
444 final CSVFormat other = (CSVFormat) obj;
445 if (delimiter != other.delimiter) {
446 return false;
447 }
448 if (quotePolicy != other.quotePolicy) {
449 return false;
450 }
451 if (quoteChar == null) {
452 if (other.quoteChar != null) {
453 return false;
454 }
455 } else if (!quoteChar.equals(other.quoteChar)) {
456 return false;
457 }
458 if (commentStart == null) {
459 if (other.commentStart != null) {
460 return false;
461 }
462 } else if (!commentStart.equals(other.commentStart)) {
463 return false;
464 }
465 if (escape == null) {
466 if (other.escape != null) {
467 return false;
468 }
469 } else if (!escape.equals(other.escape)) {
470 return false;
471 }
472 if (!Arrays.equals(header, other.header)) {
473 return false;
474 }
475 if (ignoreSurroundingSpaces != other.ignoreSurroundingSpaces) {
476 return false;
477 }
478 if (ignoreEmptyLines != other.ignoreEmptyLines) {
479 return false;
480 }
481 if (recordSeparator == null) {
482 if (other.recordSeparator != null) {
483 return false;
484 }
485 } else if (!recordSeparator.equals(other.recordSeparator)) {
486 return false;
487 }
488 return true;
489 }
490
491 /**
492 * Creates a builder based on this format.
493 *
494 * @return a new builder
495 */
496 public CSVFormatBuilder toBuilder() {
497 return new CSVFormatBuilder(this);
498 }
499
500 /**
501 * Builds CSVFormat objects.
502 */
503 public static class CSVFormatBuilder {
504
505 private char delimiter;
506 private Character quoteChar;
507 private Quote quotePolicy;
508 private Character commentStart;
509 private Character escape;
510 private boolean ignoreSurroundingSpaces; // Should leading/trailing spaces be ignored around values?
511 private boolean ignoreEmptyLines;
512 private String recordSeparator; // for outputs
513 private String[] header;
514
515 /**
516 * Creates a customized CSV format.
517 *
518 * @param delimiter
519 * the char used for value separation, must not be a line break character
520 * @param quoteChar
521 * the char used as value encapsulation marker
522 * @param quotePolicy
523 * the quote policy
524 * @param commentStart
525 * the char used for comment identification
526 * @param escape
527 * the char used to escape special characters in values
528 * @param ignoreSurroundingSpaces
529 * <tt>true</tt> when whitespaces enclosing values should be ignored
530 * @param ignoreEmptyLines
531 * <tt>true</tt> when the parser should skip empty lines
532 * @param recordSeparator
533 * the line separator to use for output
534 * @param header
535 * the header
536 * @throws IllegalArgumentException if the delimiter is a line break character
537 */
538 // package protected for use by test code
539 CSVFormatBuilder(final char delimiter, final Character quoteChar,
540 final Quote quotePolicy, final Character commentStart,
541 final Character escape, final boolean ignoreSurroundingSpaces,
542 final boolean ignoreEmptyLines, final String lineSeparator,
543 final String[] header) {
544 if (isLineBreak(delimiter)) {
545 throw new IllegalArgumentException("The delimiter cannot be a line break");
546 }
547 this.delimiter = delimiter;
548 this.quoteChar = quoteChar;
549 this.quotePolicy = quotePolicy;
550 this.commentStart = commentStart;
551 this.escape = escape;
552 this.ignoreSurroundingSpaces = ignoreSurroundingSpaces;
553 this.ignoreEmptyLines = ignoreEmptyLines;
554 this.recordSeparator = lineSeparator;
555 this.header = header;
556 }
557
558 /**
559 * Creates a CSVFormatBuilder, using the values of the given CSVFormat.
560 *
561 * @param format
562 * The format to use values from
563 */
564 @SuppressWarnings("synthetic-access") // TODO fields could be made package-protected
565 // package protected to give access without needing a synthetic accessor
566 CSVFormatBuilder(final CSVFormat format) {
567 this(format.delimiter, format.quoteChar, format.quotePolicy,
568 format.commentStart, format.escape,
569 format.ignoreSurroundingSpaces, format.ignoreEmptyLines,
570 format.recordSeparator, format.header);
571 }
572
573 /**
574 * Creates a basic CSVFormatBuilder.
575 *
576 * @param delimiter
577 * the char used for value separation, must not be a line break character
578 * @throws IllegalArgumentException if the delimiter is a line break character
579 */
580 // package protected to give access without needing a synthetic accessor
581 CSVFormatBuilder(final char delimiter){
582 this(delimiter, null, null, null, null, false, false, null, null);
583 }
584
585 /**
586 * Builds a new CSVFormat configured with the values from this builder.
587 *
588 * @return a new CSVFormat
589 */
590 public CSVFormat build() {
591 validate();
592 return new CSVFormat(delimiter, quoteChar, quotePolicy, commentStart, escape,
593 ignoreSurroundingSpaces, ignoreEmptyLines, recordSeparator, header);
594 }
595
596 /**
597 * Parses the specified content. Short-hand for:
598 * <pre>format.build().parse(in);</pre>
599 *
600 * @param in
601 * the input stream
602 * @return a CSVRecord stream
603 * @throws IOException
604 * If an I/O error occurs
605 */
606 public Iterable<CSVRecord> parse(final Reader in) throws IOException {
607 return this.build().parse(in);
608 }
609
610 /**
611 * Verifies the consistency of the parameters and throws an IllegalStateException if necessary.
612 *
613 * @throws IllegalStateException
614 */
615 private void validate() throws IllegalStateException {
616 if (quoteChar != null && delimiter == quoteChar.charValue()) {
617 throw new IllegalStateException(
618 "The quoteChar character and the delimiter cannot be the same ('" + quoteChar + "')");
619 }
620
621 if (escape != null && delimiter == escape.charValue()) {
622 throw new IllegalStateException(
623 "The escape character and the delimiter cannot be the same ('" + escape + "')");
624 }
625
626 if (commentStart != null && delimiter == commentStart.charValue()) {
627 throw new IllegalStateException(
628 "The comment start character and the delimiter cannot be the same ('" + commentStart + "')");
629 }
630
631 if (quoteChar != null && quoteChar.equals(commentStart)) {
632 throw new IllegalStateException(
633 "The comment start character and the quoteChar cannot be the same ('" + commentStart + "')");
634 }
635
636 if (escape != null && escape.equals(commentStart)) {
637 throw new IllegalStateException(
638 "The comment start and the escape character cannot be the same ('" + commentStart + "')");
639 }
640
641 if (escape == null && quotePolicy == Quote.NONE) {
642 throw new IllegalStateException("No quotes mode set but no escape character is set");
643 }
644 }
645
646 /**
647 * Sets the delimiter of the format to the specified character.
648 *
649 * @param delimiter
650 * the delimiter character
651 * @return This builder with the specified character as delimiter
652 * @throws IllegalArgumentException
653 * thrown if the specified character is a line break
654 */
655 public CSVFormatBuilder withDelimiter(final char delimiter) {
656 if (isLineBreak(delimiter)) {
657 throw new IllegalArgumentException("The delimiter cannot be a line break");
658 }
659 this.delimiter = delimiter;
660 return this;
661 }
662
663 /**
664 * Sets the quoteChar of the format to the specified character.
665 *
666 * @param quoteChar
667 * the quoteChar character
668 * @return This builder with the specified character as quoteChar
669 * @throws IllegalArgumentException
670 * thrown if the specified character is a line break
671 */
672 public CSVFormatBuilder withQuoteChar(final char quoteChar) {
673 return withQuoteChar(Character.valueOf(quoteChar));
674 }
675
676 /**
677 * Sets the quoteChar of the format to the specified character.
678 *
679 * @param quoteChar
680 * the quoteChar character
681 * @return This builder with the specified character as quoteChar
682 * @throws IllegalArgumentException
683 * thrown if the specified character is a line break
684 */
685 public CSVFormatBuilder withQuoteChar(final Character quoteChar) {
686 if (isLineBreak(quoteChar)) {
687 throw new IllegalArgumentException("The quoteChar cannot be a line break");
688 }
689 this.quoteChar = quoteChar;
690 return this;
691 }
692
693 /**
694 * Sets the comment start marker of the format to the specified character.
695 *
696 * Note that the comment introducer character is only recognised at the start of a line.
697 *
698 * @param commentStart
699 * the comment start marker
700 * @return This builder with the specified character as the comment start marker
701 * @throws IllegalArgumentException
702 * thrown if the specified character is a line break
703 */
704 public CSVFormatBuilder withCommentStart(final char commentStart) {
705 return withCommentStart(Character.valueOf(commentStart));
706 }
707
708 /**
709 * Sets the comment start marker of the format to the specified character.
710 *
711 * Note that the comment introducer character is only recognised at the start of a line.
712 *
713 * @param commentStart
714 * the comment start marker
715 * @return This builder with the specified character as the comment start marker
716 * @throws IllegalArgumentException
717 * thrown if the specified character is a line break
718 */
719 public CSVFormatBuilder withCommentStart(final Character commentStart) {
720 if (isLineBreak(commentStart)) {
721 throw new IllegalArgumentException("The comment start character cannot be a line break");
722 }
723 this.commentStart = commentStart;
724 return this;
725 }
726
727 /**
728 * Sets the escape character of the format to the specified character.
729 *
730 * @param escape
731 * the escape character
732 * @return This builder with the specified character as the escape character
733 * @throws IllegalArgumentException
734 * thrown if the specified character is a line break
735 */
736 public CSVFormatBuilder withEscape(final char escape) {
737 return withEscape(Character.valueOf(escape));
738 }
739
740 /**
741 * Sets the escape character of the format to the specified character.
742 *
743 * @param escape
744 * the escape character
745 * @return This builder with the specified character as the escape character
746 * @throws IllegalArgumentException
747 * thrown if the specified character is a line break
748 */
749 public CSVFormatBuilder withEscape(final Character escape) {
750 if (isLineBreak(escape)) {
751 throw new IllegalArgumentException("The escape character cannot be a line break");
752 }
753 this.escape = escape;
754 return this;
755 }
756
757 /**
758 * Sets the header of the format. The header can either be parsed automatically from the
759 * input file with:
760 *
761 * <pre>
762 * CSVFormat format = aformat.withHeader();
763 * </pre>
764 *
765 * or specified manually with:
766 *
767 * <pre>
768 * CSVFormat format = aformat.withHeader("name", "email", "phone");
769 * </pre>
770 *
771 * @param header
772 * the header, <tt>null</tt> if disabled, empty if parsed automatically, user specified otherwise.
773 *
774 * @return This builder with the specified header
775 */
776 public CSVFormatBuilder withHeader(final String... header) {
777 this.header = header;
778 return this;
779 }
780
781 /**
782 * Sets the trimming behavior of the format.
783 *
784 * @param ignoreSurroundingSpaces
785 * the trimming behavior, <tt>true</tt> to remove the surrounding spaces, <tt>false</tt> to leave the
786 * spaces as is.
787 * @return This builder with the specified trimming behavior.
788 */
789 public CSVFormatBuilder withIgnoreSurroundingSpaces(final boolean ignoreSurroundingSpaces) {
790 this.ignoreSurroundingSpaces = ignoreSurroundingSpaces;
791 return this;
792 }
793
794 /**
795 * Sets the empty line skipping behavior of the format.
796 *
797 * @param ignoreEmptyLines
798 * the empty line skipping behavior, <tt>true</tt> to ignore the empty lines between the records,
799 * <tt>false</tt> to translate empty lines to empty records.
800 * @return This builder with the specified empty line skipping behavior.
801 */
802 public CSVFormatBuilder withIgnoreEmptyLines(final boolean ignoreEmptyLines) {
803 this.ignoreEmptyLines = ignoreEmptyLines;
804 return this;
805 }
806
807 /**
808 * Sets the record separator of the format to the specified character.
809 *
810 * @param recordSeparator
811 * the record separator to use for output.
812 *
813 * @return This builder with the the specified output record separator
814 */
815 public CSVFormatBuilder withRecordSeparator(final char recordSeparator) {
816 return withRecordSeparator(String.valueOf(recordSeparator));
817 }
818
819 /**
820 * Sets the record separator of the format to the specified String.
821 *
822 * @param recordSeparator
823 * the record separator to use for output.
824 *
825 * @return This builder with the the specified output record separator
826 */
827 public CSVFormatBuilder withRecordSeparator(final String recordSeparator) {
828 this.recordSeparator = recordSeparator;
829 return this;
830 }
831
832 /**
833 * Sets the output quote policy of the format to the specified value.
834 *
835 * @param quotePolicy
836 * the quote policy to use for output.
837 *
838 * @return This builder with the specified quote policy
839 */
840 public CSVFormatBuilder withQuotePolicy(final Quote quotePolicy) {
841 this.quotePolicy = quotePolicy;
842 return this;
843 }
844 }
845 }