View Javadoc

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(&quot;Col1&quot;, &quot;Col2&quot;, &quot;Col3&quot;).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(&quot;Col1&quot;, &quot;Col2&quot;, &quot;Col3&quot;).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(&quot;name&quot;, &quot;email&quot;, &quot;phone&quot;);
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 }