001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018package org.apache.commons.csv;
019
020import static org.apache.commons.csv.Constants.BACKSLASH;
021import static org.apache.commons.csv.Constants.COMMA;
022import static org.apache.commons.csv.Constants.COMMENT;
023import static org.apache.commons.csv.Constants.CR;
024import static org.apache.commons.csv.Constants.CRLF;
025import static org.apache.commons.csv.Constants.DOUBLE_QUOTE_CHAR;
026import static org.apache.commons.csv.Constants.LF;
027import static org.apache.commons.csv.Constants.PIPE;
028import static org.apache.commons.csv.Constants.SP;
029import static org.apache.commons.csv.Constants.TAB;
030
031import java.io.File;
032import java.io.FileOutputStream;
033import java.io.IOException;
034import java.io.OutputStreamWriter;
035import java.io.Reader;
036import java.io.Serializable;
037import java.io.StringWriter;
038import java.nio.charset.Charset;
039import java.nio.file.Path;
040import java.sql.ResultSet;
041import java.sql.ResultSetMetaData;
042import java.sql.SQLException;
043import java.util.Arrays;
044import java.util.HashSet;
045import java.util.Set;
046
047/**
048 * Specifies the format of a CSV file and parses input.
049 *
050 * <h2>Using predefined formats</h2>
051 *
052 * <p>
053 * You can use one of the predefined formats:
054 * </p>
055 *
056 * <ul>
057 * <li>{@link #DEFAULT}</li>
058 * <li>{@link #EXCEL}</li>
059 * <li>{@link #MYSQL}</li>
060 * <li>{@link #RFC4180}</li>
061 * <li>{@link #TDF}</li>
062 * </ul>
063 *
064 * <p>
065 * For example:
066 * </p>
067 *
068 * <pre>
069 * CSVParser parser = CSVFormat.EXCEL.parse(reader);
070 * </pre>
071 *
072 * <p>
073 * The {@link CSVParser} provides static methods to parse other input types, for example:
074 * </p>
075 *
076 * <pre>
077 * CSVParser parser = CSVParser.parse(file, StandardCharsets.US_ASCII, CSVFormat.EXCEL);
078 * </pre>
079 *
080 * <h2>Defining formats</h2>
081 *
082 * <p>
083 * You can extend a format by calling the {@code with} methods. For example:
084 * </p>
085 *
086 * <pre>
087 * CSVFormat.EXCEL.withNullString(&quot;N/A&quot;).withIgnoreSurroundingSpaces(true);
088 * </pre>
089 *
090 * <h2>Defining column names</h2>
091 *
092 * <p>
093 * To define the column names you want to use to access records, write:
094 * </p>
095 *
096 * <pre>
097 * CSVFormat.EXCEL.withHeader(&quot;Col1&quot;, &quot;Col2&quot;, &quot;Col3&quot;);
098 * </pre>
099 *
100 * <p>
101 * Calling {@link #withHeader(String...)} let's you use the given names to address values in a {@link CSVRecord}, and
102 * assumes that your CSV source does not contain a first record that also defines column names.
103 *
104 * If it does, then you are overriding this metadata with your names and you should skip the first record by calling
105 * {@link #withSkipHeaderRecord(boolean)} with {@code true}.
106 * </p>
107 *
108 * <h2>Parsing</h2>
109 *
110 * <p>
111 * You can use a format directly to parse a reader. For example, to parse an Excel file with columns header, write:
112 * </p>
113 *
114 * <pre>
115 * Reader in = ...;
116 * CSVFormat.EXCEL.withHeader(&quot;Col1&quot;, &quot;Col2&quot;, &quot;Col3&quot;).parse(in);
117 * </pre>
118 *
119 * <p>
120 * For other input types, like resources, files, and URLs, use the static methods on {@link CSVParser}.
121 * </p>
122 *
123 * <h2>Referencing columns safely</h2>
124 *
125 * <p>
126 * If your source contains a header record, you can simplify your code and safely reference columns, by using
127 * {@link #withHeader(String...)} with no arguments:
128 * </p>
129 *
130 * <pre>
131 * CSVFormat.EXCEL.withHeader();
132 * </pre>
133 *
134 * <p>
135 * This causes the parser to read the first record and use its values as column names.
136 *
137 * Then, call one of the {@link CSVRecord} get method that takes a String column name argument:
138 * </p>
139 *
140 * <pre>
141 * String value = record.get(&quot;Col1&quot;);
142 * </pre>
143 *
144 * <p>
145 * This makes your code impervious to changes in column order in the CSV file.
146 * </p>
147 *
148 * <h2>Notes</h2>
149 *
150 * <p>
151 * This class is immutable.
152 * </p>
153 *
154 * @version $Id$
155 */
156public final class CSVFormat implements Serializable {
157
158    /**
159     * Predefines formats.
160     *
161     * @since 1.2
162     */
163    public enum Predefined {
164
165        /**
166         * @see CSVFormat#DEFAULT
167         */
168        Default(CSVFormat.DEFAULT),
169
170        /**
171         * @see CSVFormat#EXCEL
172         */
173        Excel(CSVFormat.EXCEL),
174
175        /**
176         * @see CSVFormat#INFORMIX_UNLOAD
177         * @since 1.3
178         */
179        InformixUnload(CSVFormat.INFORMIX_UNLOAD),
180
181        /**
182         * @see CSVFormat#INFORMIX_UNLOAD_CSV
183         * @since 1.3
184         */
185        InformixUnloadCsv(CSVFormat.INFORMIX_UNLOAD_CSV),
186
187        /**
188         * @see CSVFormat#MYSQL
189         */
190        MySQL(CSVFormat.MYSQL),
191
192        /**
193         * @see CSVFormat#RFC4180
194         */
195        RFC4180(CSVFormat.RFC4180),
196
197        /**
198         * @see CSVFormat#TDF
199         */
200        TDF(CSVFormat.TDF);
201
202        private final CSVFormat format;
203
204        Predefined(final CSVFormat format) {
205            this.format = format;
206        }
207
208        /**
209         * Gets the format.
210         *
211         * @return the format.
212         */
213        public CSVFormat getFormat() {
214            return format;
215        }
216    }
217
218    /**
219     * Standard comma separated format, as for {@link #RFC4180} but allowing empty lines.
220     *
221     * <p>
222     * Settings are:
223     * </p>
224     * <ul>
225     * <li>withDelimiter(',')</li>
226     * <li>withQuote('"')</li>
227     * <li>withRecordSeparator("\r\n")</li>
228     * <li>withIgnoreEmptyLines(true)</li>
229     * </ul>
230     *
231     * @see Predefined#Default
232     */
233    public static final CSVFormat DEFAULT = new CSVFormat(COMMA, DOUBLE_QUOTE_CHAR, null, null, null, false, true, CRLF,
234            null, null, null, false, false, false, false, false);
235
236    /**
237     * Excel file format (using a comma as the value delimiter). Note that the actual value delimiter used by Excel is
238     * locale dependent, it might be necessary to customize this format to accommodate to your regional settings.
239     *
240     * <p>
241     * For example for parsing or generating a CSV file on a French system the following format will be used:
242     * </p>
243     *
244     * <pre>
245     * CSVFormat fmt = CSVFormat.EXCEL.withDelimiter(';');
246     * </pre>
247     *
248     * <p>
249     * Settings are:
250     * </p>
251     * <ul>
252     * <li>{@link #withDelimiter(char) withDelimiter(',')}</li>
253     * <li>{@link #withQuote(char) withQuote('"')}</li>
254     * <li>{@link #withRecordSeparator(String) withRecordSeparator("\r\n")}</li>
255     * <li>{@link #withIgnoreEmptyLines(boolean) withIgnoreEmptyLines(false)}</li>
256     * <li>{@link #withAllowMissingColumnNames(boolean) withAllowMissingColumnNames(true)}</li>
257     * </ul>
258     * <p>
259     * Note: this is currently like {@link #RFC4180} plus {@link #withAllowMissingColumnNames(boolean)
260     * withAllowMissingColumnNames(true)}.
261     * </p>
262     *
263     * @see Predefined#Excel
264     */
265    public static final CSVFormat EXCEL = DEFAULT.withIgnoreEmptyLines(false).withAllowMissingColumnNames();
266
267    /**
268     * Default Informix CSV UNLOAD format used by the {@code UNLOAD TO file_name} operation.
269     *
270     * <p>
271     * This is a comma-delimited format with a LF character as the line separator. Values are not quoted and special
272     * characters are escaped with {@code '\'}. The default NULL string is {@code "\\N"}.
273     * </p>
274     *
275     * <p>
276     * Settings are:
277     * </p>
278     * <ul>
279     * <li>withDelimiter(',')</li>
280     * <li>withQuote("\"")</li>
281     * <li>withRecordSeparator('\n')</li>
282     * <li>withEscape('\\')</li>
283     * </ul>
284     *
285     * @see Predefined#MySQL
286     * @see <a href=
287     *      "http://www.ibm.com/support/knowledgecenter/SSBJG3_2.5.0/com.ibm.gen_busug.doc/c_fgl_InOutSql_UNLOAD.htm">
288     *      http://www.ibm.com/support/knowledgecenter/SSBJG3_2.5.0/com.ibm.gen_busug.doc/c_fgl_InOutSql_UNLOAD.htm</a>
289     * @since 1.3
290     */
291    public static final CSVFormat INFORMIX_UNLOAD = DEFAULT.withDelimiter(PIPE).withEscape(BACKSLASH)
292            .withQuote(DOUBLE_QUOTE_CHAR).withRecordSeparator(LF);
293
294    /**
295     * Default Informix CSV UNLOAD format used by the {@code UNLOAD TO file_name} operation (escaping is disabled.)
296     *
297     * <p>
298     * This is a comma-delimited format with a LF character as the line separator. Values are not quoted and special
299     * characters are escaped with {@code '\'}. The default NULL string is {@code "\\N"}.
300     * </p>
301     *
302     * <p>
303     * Settings are:
304     * </p>
305     * <ul>
306     * <li>withDelimiter(',')</li>
307     * <li>withQuote("\"")</li>
308     * <li>withRecordSeparator('\n')</li>
309     * </ul>
310     *
311     * @see Predefined#MySQL
312     * @see <a href=
313     *      "http://www.ibm.com/support/knowledgecenter/SSBJG3_2.5.0/com.ibm.gen_busug.doc/c_fgl_InOutSql_UNLOAD.htm">
314     *      http://www.ibm.com/support/knowledgecenter/SSBJG3_2.5.0/com.ibm.gen_busug.doc/c_fgl_InOutSql_UNLOAD.htm</a>
315     * @since 1.3
316     */
317    public static final CSVFormat INFORMIX_UNLOAD_CSV = DEFAULT.withDelimiter(COMMA).withQuote(DOUBLE_QUOTE_CHAR)
318            .withRecordSeparator(LF);
319
320    /**
321     * Default MySQL format used by the {@code SELECT INTO OUTFILE} and {@code LOAD DATA INFILE} operations.
322     *
323     * <p>
324     * This is a tab-delimited format with a LF character as the line separator. Values are not quoted and special
325     * characters are escaped with {@code '\'}. The default NULL string is {@code "\\N"}.
326     * </p>
327     *
328     * <p>
329     * Settings are:
330     * </p>
331     * <ul>
332     * <li>withDelimiter('\t')</li>
333     * <li>withQuote(null)</li>
334     * <li>withRecordSeparator('\n')</li>
335     * <li>withIgnoreEmptyLines(false)</li>
336     * <li>withEscape('\\')</li>
337     * <li>withNullString("\\N")</li>
338     * </ul>
339     *
340     * @see Predefined#MySQL
341     * @see <a href="http://dev.mysql.com/doc/refman/5.1/en/load-data.html"> http://dev.mysql.com/doc/refman/5.1/en/load
342     *      -data.html</a>
343     */
344    public static final CSVFormat MYSQL = DEFAULT.withDelimiter(TAB).withEscape(BACKSLASH).withIgnoreEmptyLines(false)
345            .withQuote(null).withRecordSeparator(LF).withNullString("\\N");
346
347    /**
348     * Comma separated format as defined by <a href="http://tools.ietf.org/html/rfc4180">RFC 4180</a>.
349     *
350     * <p>
351     * Settings are:
352     * </p>
353     * <ul>
354     * <li>withDelimiter(',')</li>
355     * <li>withQuote('"')</li>
356     * <li>withRecordSeparator("\r\n")</li>
357     * <li>withIgnoreEmptyLines(false)</li>
358     * </ul>
359     *
360     * @see Predefined#RFC4180
361     */
362    public static final CSVFormat RFC4180 = DEFAULT.withIgnoreEmptyLines(false);
363
364    private static final long serialVersionUID = 1L;
365
366    /**
367     * Tab-delimited format.
368     *
369     * <p>
370     * Settings are:
371     * </p>
372     * <ul>
373     * <li>withDelimiter('\t')</li>
374     * <li>withQuote('"')</li>
375     * <li>withRecordSeparator("\r\n")</li>
376     * <li>withIgnoreSurroundingSpaces(true)</li>
377     * </ul>
378     *
379     * @see Predefined#TDF
380     */
381    public static final CSVFormat TDF = DEFAULT.withDelimiter(TAB).withIgnoreSurroundingSpaces();
382
383    /**
384     * Returns true if the given character is a line break character.
385     *
386     * @param c
387     *            the character to check
388     *
389     * @return true if <code>c</code> is a line break character
390     */
391    private static boolean isLineBreak(final char c) {
392        return c == LF || c == CR;
393    }
394
395    /**
396     * Returns true if the given character is a line break character.
397     *
398     * @param c
399     *            the character to check, may be null
400     *
401     * @return true if <code>c</code> is a line break character (and not null)
402     */
403    private static boolean isLineBreak(final Character c) {
404        return c != null && isLineBreak(c.charValue());
405    }
406
407    /**
408     * Creates a new CSV format with the specified delimiter.
409     *
410     * <p>
411     * Use this method if you want to create a CSVFormat from scratch. All fields but the delimiter will be initialized
412     * with null/false.
413     * </p>
414     *
415     * @param delimiter
416     *            the char used for value separation, must not be a line break character
417     * @return a new CSV format.
418     * @throws IllegalArgumentException
419     *             if the delimiter is a line break character
420     *
421     * @see #DEFAULT
422     * @see #RFC4180
423     * @see #MYSQL
424     * @see #EXCEL
425     * @see #TDF
426     */
427    public static CSVFormat newFormat(final char delimiter) {
428        return new CSVFormat(delimiter, null, null, null, null, false, false, null, null, null, null, false, false,
429                false, false, false);
430    }
431
432    /**
433     * Gets one of the predefined formats from {@link CSVFormat.Predefined}.
434     *
435     * @param format
436     *            name
437     * @return one of the predefined formats
438     * @since 1.2
439     */
440    public static CSVFormat valueOf(final String format) {
441        return CSVFormat.Predefined.valueOf(format).getFormat();
442    }
443
444    private final boolean allowMissingColumnNames;
445
446    private final Character commentMarker; // null if commenting is disabled
447
448    private final char delimiter;
449
450    private final Character escapeCharacter; // null if escaping is disabled
451
452    private final String[] header; // array of header column names
453
454    private final String[] headerComments; // array of header comment lines
455
456    private final boolean ignoreEmptyLines;
457
458    private final boolean ignoreHeaderCase; // should ignore header names case
459
460    private final boolean ignoreSurroundingSpaces; // Should leading/trailing spaces be ignored around values?
461
462    private final String nullString; // the string to be used for null values
463
464    private final Character quoteCharacter; // null if quoting is disabled
465
466    private final QuoteMode quoteMode;
467
468    private final String recordSeparator; // for outputs
469
470    private final boolean skipHeaderRecord;
471
472    private final boolean trailingDelimiter;
473
474    private final boolean trim;
475
476    /**
477     * Creates a customized CSV format.
478     *
479     * @param delimiter
480     *            the char used for value separation, must not be a line break character
481     * @param quoteChar
482     *            the Character used as value encapsulation marker, may be {@code null} to disable
483     * @param quoteMode
484     *            the quote mode
485     * @param commentStart
486     *            the Character used for comment identification, may be {@code null} to disable
487     * @param escape
488     *            the Character used to escape special characters in values, may be {@code null} to disable
489     * @param ignoreSurroundingSpaces
490     *            {@code true} when whitespaces enclosing values should be ignored
491     * @param ignoreEmptyLines
492     *            {@code true} when the parser should skip empty lines
493     * @param recordSeparator
494     *            the line separator to use for output
495     * @param nullString
496     *            the line separator to use for output
497     * @param headerComments
498     *            the comments to be printed by the Printer before the actual CSV data
499     * @param header
500     *            the header
501     * @param skipHeaderRecord
502     *            TODO
503     * @param allowMissingColumnNames
504     *            TODO
505     * @param ignoreHeaderCase
506     *            TODO
507     * @param trim
508     *            TODO
509     * @param trailingDelimiter
510     *            TODO
511     * @throws IllegalArgumentException
512     *             if the delimiter is a line break character
513     */
514    private CSVFormat(final char delimiter, final Character quoteChar, final QuoteMode quoteMode,
515            final Character commentStart, final Character escape, final boolean ignoreSurroundingSpaces,
516            final boolean ignoreEmptyLines, final String recordSeparator, final String nullString,
517            final Object[] headerComments, final String[] header, final boolean skipHeaderRecord,
518            final boolean allowMissingColumnNames, final boolean ignoreHeaderCase, final boolean trim,
519            final boolean trailingDelimiter) {
520        this.delimiter = delimiter;
521        this.quoteCharacter = quoteChar;
522        this.quoteMode = quoteMode;
523        this.commentMarker = commentStart;
524        this.escapeCharacter = escape;
525        this.ignoreSurroundingSpaces = ignoreSurroundingSpaces;
526        this.allowMissingColumnNames = allowMissingColumnNames;
527        this.ignoreEmptyLines = ignoreEmptyLines;
528        this.recordSeparator = recordSeparator;
529        this.nullString = nullString;
530        this.headerComments = toStringArray(headerComments);
531        this.header = header == null ? null : header.clone();
532        this.skipHeaderRecord = skipHeaderRecord;
533        this.ignoreHeaderCase = ignoreHeaderCase;
534        this.trailingDelimiter = trailingDelimiter;
535        this.trim = trim;
536        validate();
537    }
538
539    @Override
540    public boolean equals(final Object obj) {
541        if (this == obj) {
542            return true;
543        }
544        if (obj == null) {
545            return false;
546        }
547        if (getClass() != obj.getClass()) {
548            return false;
549        }
550
551        final CSVFormat other = (CSVFormat) obj;
552        if (delimiter != other.delimiter) {
553            return false;
554        }
555        if (quoteMode != other.quoteMode) {
556            return false;
557        }
558        if (quoteCharacter == null) {
559            if (other.quoteCharacter != null) {
560                return false;
561            }
562        } else if (!quoteCharacter.equals(other.quoteCharacter)) {
563            return false;
564        }
565        if (commentMarker == null) {
566            if (other.commentMarker != null) {
567                return false;
568            }
569        } else if (!commentMarker.equals(other.commentMarker)) {
570            return false;
571        }
572        if (escapeCharacter == null) {
573            if (other.escapeCharacter != null) {
574                return false;
575            }
576        } else if (!escapeCharacter.equals(other.escapeCharacter)) {
577            return false;
578        }
579        if (nullString == null) {
580            if (other.nullString != null) {
581                return false;
582            }
583        } else if (!nullString.equals(other.nullString)) {
584            return false;
585        }
586        if (!Arrays.equals(header, other.header)) {
587            return false;
588        }
589        if (ignoreSurroundingSpaces != other.ignoreSurroundingSpaces) {
590            return false;
591        }
592        if (ignoreEmptyLines != other.ignoreEmptyLines) {
593            return false;
594        }
595        if (skipHeaderRecord != other.skipHeaderRecord) {
596            return false;
597        }
598        if (recordSeparator == null) {
599            if (other.recordSeparator != null) {
600                return false;
601            }
602        } else if (!recordSeparator.equals(other.recordSeparator)) {
603            return false;
604        }
605        return true;
606    }
607
608    /**
609     * Formats the specified values.
610     *
611     * @param values
612     *            the values to format
613     * @return the formatted values
614     */
615    public String format(final Object... values) {
616        final StringWriter out = new StringWriter();
617        try (final CSVPrinter csvPrinter = new CSVPrinter(out, this)) {
618            csvPrinter.printRecord(values);
619            return out.toString().trim();
620        } catch (final IOException e) {
621            // should not happen because a StringWriter does not do IO.
622            throw new IllegalStateException(e);
623        }
624    }
625
626    /**
627     * Specifies whether missing column names are allowed when parsing the header line.
628     *
629     * @return {@code true} if missing column names are allowed when parsing the header line, {@code false} to throw an
630     *         {@link IllegalArgumentException}.
631     */
632    public boolean getAllowMissingColumnNames() {
633        return allowMissingColumnNames;
634    }
635
636    /**
637     * Returns the character marking the start of a line comment.
638     *
639     * @return the comment start marker, may be {@code null}
640     */
641    public Character getCommentMarker() {
642        return commentMarker;
643    }
644
645    /**
646     * Returns the character delimiting the values (typically ';', ',' or '\t').
647     *
648     * @return the delimiter character
649     */
650    public char getDelimiter() {
651        return delimiter;
652    }
653
654    /**
655     * Returns the escape character.
656     *
657     * @return the escape character, may be {@code null}
658     */
659    public Character getEscapeCharacter() {
660        return escapeCharacter;
661    }
662
663    /**
664     * Returns a copy of the header array.
665     *
666     * @return a copy of the header array; {@code null} if disabled, the empty array if to be read from the file
667     */
668    public String[] getHeader() {
669        return header != null ? header.clone() : null;
670    }
671
672    /**
673     * Returns a copy of the header comment array.
674     *
675     * @return a copy of the header comment array; {@code null} if disabled.
676     */
677    public String[] getHeaderComments() {
678        return headerComments != null ? headerComments.clone() : null;
679    }
680
681    /**
682     * Specifies whether empty lines between records are ignored when parsing input.
683     *
684     * @return {@code true} if empty lines between records are ignored, {@code false} if they are turned into empty
685     *         records.
686     */
687    public boolean getIgnoreEmptyLines() {
688        return ignoreEmptyLines;
689    }
690
691    /**
692     * Specifies whether header names will be accessed ignoring case.
693     *
694     * @return {@code true} if header names cases are ignored, {@code false} if they are case sensitive.
695     * @since 1.3
696     */
697    public boolean getIgnoreHeaderCase() {
698        return ignoreHeaderCase;
699    }
700
701    /**
702     * Specifies whether spaces around values are ignored when parsing input.
703     *
704     * @return {@code true} if spaces around values are ignored, {@code false} if they are treated as part of the value.
705     */
706    public boolean getIgnoreSurroundingSpaces() {
707        return ignoreSurroundingSpaces;
708    }
709
710    /**
711     * Gets the String to convert to and from {@code null}.
712     * <ul>
713     * <li><strong>Reading:</strong> Converts strings equal to the given {@code nullString} to {@code null} when reading
714     * records.</li>
715     * <li><strong>Writing:</strong> Writes {@code null} as the given {@code nullString} when writing records.</li>
716     * </ul>
717     *
718     * @return the String to convert to and from {@code null}. No substitution occurs if {@code null}
719     */
720    public String getNullString() {
721        return nullString;
722    }
723
724    /**
725     * Returns the character used to encapsulate values containing special characters.
726     *
727     * @return the quoteChar character, may be {@code null}
728     */
729    public Character getQuoteCharacter() {
730        return quoteCharacter;
731    }
732
733    /**
734     * Returns the quote policy output fields.
735     *
736     * @return the quote policy
737     */
738    public QuoteMode getQuoteMode() {
739        return quoteMode;
740    }
741
742    /**
743     * Returns the record separator delimiting output records.
744     *
745     * @return the record separator
746     */
747    public String getRecordSeparator() {
748        return recordSeparator;
749    }
750
751    /**
752     * Returns whether to skip the header record.
753     *
754     * @return whether to skip the header record.
755     */
756    public boolean getSkipHeaderRecord() {
757        return skipHeaderRecord;
758    }
759
760    /**
761     * Returns whether to add a trailing delimiter.
762     *
763     * @return whether to add a trailing delimiter.
764     * @since 1.3
765     */
766    public boolean getTrailingDelimiter() {
767        return trailingDelimiter;
768    }
769
770    /**
771     * Returns whether to trim leading and trailing blanks.
772     *
773     * @return whether to trim leading and trailing blanks.
774     */
775    public boolean getTrim() {
776        return trim;
777    }
778
779    @Override
780    public int hashCode() {
781        final int prime = 31;
782        int result = 1;
783
784        result = prime * result + delimiter;
785        result = prime * result + ((quoteMode == null) ? 0 : quoteMode.hashCode());
786        result = prime * result + ((quoteCharacter == null) ? 0 : quoteCharacter.hashCode());
787        result = prime * result + ((commentMarker == null) ? 0 : commentMarker.hashCode());
788        result = prime * result + ((escapeCharacter == null) ? 0 : escapeCharacter.hashCode());
789        result = prime * result + ((nullString == null) ? 0 : nullString.hashCode());
790        result = prime * result + (ignoreSurroundingSpaces ? 1231 : 1237);
791        result = prime * result + (ignoreHeaderCase ? 1231 : 1237);
792        result = prime * result + (ignoreEmptyLines ? 1231 : 1237);
793        result = prime * result + (skipHeaderRecord ? 1231 : 1237);
794        result = prime * result + ((recordSeparator == null) ? 0 : recordSeparator.hashCode());
795        result = prime * result + Arrays.hashCode(header);
796        return result;
797    }
798
799    /**
800     * Specifies whether comments are supported by this format.
801     *
802     * Note that the comment introducer character is only recognized at the start of a line.
803     *
804     * @return {@code true} is comments are supported, {@code false} otherwise
805     */
806    public boolean isCommentMarkerSet() {
807        return commentMarker != null;
808    }
809
810    /**
811     * Returns whether escape are being processed.
812     *
813     * @return {@code true} if escapes are processed
814     */
815    public boolean isEscapeCharacterSet() {
816        return escapeCharacter != null;
817    }
818
819    /**
820     * Returns whether a nullString has been defined.
821     *
822     * @return {@code true} if a nullString is defined
823     */
824    public boolean isNullStringSet() {
825        return nullString != null;
826    }
827
828    /**
829     * Returns whether a quoteChar has been defined.
830     *
831     * @return {@code true} if a quoteChar is defined
832     */
833    public boolean isQuoteCharacterSet() {
834        return quoteCharacter != null;
835    }
836
837    /**
838     * Parses the specified content.
839     *
840     * <p>
841     * See also the various static parse methods on {@link CSVParser}.
842     * </p>
843     *
844     * @param in
845     *            the input stream
846     * @return a parser over a stream of {@link CSVRecord}s.
847     * @throws IOException
848     *             If an I/O error occurs
849     */
850    public CSVParser parse(final Reader in) throws IOException {
851        return new CSVParser(in, this);
852    }
853
854    /**
855     * Prints to the specified output.
856     *
857     * <p>
858     * See also {@link CSVPrinter}.
859     * </p>
860     *
861     * @param out
862     *            the output
863     * @return a printer to an output
864     * @throws IOException
865     *             thrown if the optional header cannot be printed.
866     */
867    public CSVPrinter print(final Appendable out) throws IOException {
868        return new CSVPrinter(out, this);
869    }
870
871    /**
872     * Prints to the specified output.
873     *
874     * <p>
875     * See also {@link CSVPrinter}.
876     * </p>
877     *
878     * @param out
879     *            the output
880     * @param charset 
881     *            A charset
882     * @return a printer to an output
883     * @throws IOException
884     *             thrown if the optional header cannot be printed.
885     * @since 1.5
886     */
887    public CSVPrinter print(final File out, Charset charset) throws IOException {
888        // The writer will be closed when close() is called.
889        return new CSVPrinter(new OutputStreamWriter(new FileOutputStream(out), charset), this);
890    }
891
892    /**
893     * Prints to the specified output.
894     *
895     * <p>
896     * See also {@link CSVPrinter}.
897     * </p>
898     *
899     * @param out
900     *            the output
901     * @param charset 
902     *            A charset
903     * @return a printer to an output
904     * @throws IOException
905     *             thrown if the optional header cannot be printed.
906     * @since 1.5
907     */
908    public CSVPrinter print(final Path out, Charset charset) throws IOException {
909        return print(out.toFile(), charset);
910    }
911
912    /**
913     * Prints the {@code value} as the next value on the line to {@code out}. The value will be escaped or encapsulated
914     * as needed. Useful when one wants to avoid creating CSVPrinters.
915     *
916     * @param value
917     *            value to output.
918     * @param out
919     *            where to print the value
920     * @param newRecord
921     *            if this a new record
922     * @throws IOException
923     *             If an I/O error occurs
924     * @since 1.4
925     */
926    public void print(final Object value, final Appendable out, final boolean newRecord) throws IOException {
927        // null values are considered empty
928        // Only call CharSequence.toString() if you have to, helps GC-free use cases.
929        CharSequence charSequence;
930        if (value == null) {
931            charSequence = nullString == null ? Constants.EMPTY : nullString;
932        } else {
933            charSequence = value instanceof CharSequence ? (CharSequence) value : value.toString();
934        }
935        charSequence = getTrim() ? trim(charSequence) : charSequence;
936        this.print(value, charSequence, 0, charSequence.length(), out, newRecord);
937    }
938
939    private void print(final Object object, final CharSequence value, final int offset, final int len,
940            final Appendable out, final boolean newRecord) throws IOException {
941        if (!newRecord) {
942            out.append(getDelimiter());
943        }
944        if (object == null) {
945            out.append(value);
946        } else if (isQuoteCharacterSet()) {
947            // the original object is needed so can check for Number
948            printAndQuote(object, value, offset, len, out, newRecord);
949        } else if (isEscapeCharacterSet()) {
950            printAndEscape(value, offset, len, out);
951        } else {
952            out.append(value, offset, offset + len);
953        }
954    }
955
956    /*
957     * Note: must only be called if escaping is enabled, otherwise will generate NPE
958     */
959    private void printAndEscape(final CharSequence value, final int offset, final int len, final Appendable out)
960            throws IOException {
961        int start = offset;
962        int pos = offset;
963        final int end = offset + len;
964
965        final char delim = getDelimiter();
966        final char escape = getEscapeCharacter().charValue();
967
968        while (pos < end) {
969            char c = value.charAt(pos);
970            if (c == CR || c == LF || c == delim || c == escape) {
971                // write out segment up until this char
972                if (pos > start) {
973                    out.append(value, start, pos);
974                }
975                if (c == LF) {
976                    c = 'n';
977                } else if (c == CR) {
978                    c = 'r';
979                }
980
981                out.append(escape);
982                out.append(c);
983
984                start = pos + 1; // start on the current char after this one
985            }
986
987            pos++;
988        }
989
990        // write last segment
991        if (pos > start) {
992            out.append(value, start, pos);
993        }
994    }
995
996    /*
997     * Note: must only be called if quoting is enabled, otherwise will generate NPE
998     */
999    // the original object is needed so can check for Number
1000    private void printAndQuote(final Object object, final CharSequence value, final int offset, final int len,
1001            final Appendable out, final boolean newRecord) throws IOException {
1002        boolean quote = false;
1003        int start = offset;
1004        int pos = offset;
1005        final int end = offset + len;
1006
1007        final char delimChar = getDelimiter();
1008        final char quoteChar = getQuoteCharacter().charValue();
1009
1010        QuoteMode quoteModePolicy = getQuoteMode();
1011        if (quoteModePolicy == null) {
1012            quoteModePolicy = QuoteMode.MINIMAL;
1013        }
1014        switch (quoteModePolicy) {
1015        case ALL:
1016            quote = true;
1017            break;
1018        case NON_NUMERIC:
1019            quote = !(object instanceof Number);
1020            break;
1021        case NONE:
1022            // Use the existing escaping code
1023            printAndEscape(value, offset, len, out);
1024            return;
1025        case MINIMAL:
1026            if (len <= 0) {
1027                // always quote an empty token that is the first
1028                // on the line, as it may be the only thing on the
1029                // line. If it were not quoted in that case,
1030                // an empty line has no tokens.
1031                if (newRecord) {
1032                    quote = true;
1033                }
1034            } else {
1035                char c = value.charAt(pos);
1036
1037                // TODO where did this rule come from?
1038                if (newRecord && (c < '0' || c > '9' && c < 'A' || c > 'Z' && c < 'a' || c > 'z')) {
1039                    quote = true;
1040                } else if (c <= COMMENT) {
1041                    // Some other chars at the start of a value caused the parser to fail, so for now
1042                    // encapsulate if we start in anything less than '#'. We are being conservative
1043                    // by including the default comment char too.
1044                    quote = true;
1045                } else {
1046                    while (pos < end) {
1047                        c = value.charAt(pos);
1048                        if (c == LF || c == CR || c == quoteChar || c == delimChar) {
1049                            quote = true;
1050                            break;
1051                        }
1052                        pos++;
1053                    }
1054
1055                    if (!quote) {
1056                        pos = end - 1;
1057                        c = value.charAt(pos);
1058                        // Some other chars at the end caused the parser to fail, so for now
1059                        // encapsulate if we end in anything less than ' '
1060                        if (c <= SP) {
1061                            quote = true;
1062                        }
1063                    }
1064                }
1065            }
1066
1067            if (!quote) {
1068                // no encapsulation needed - write out the original value
1069                out.append(value, start, end);
1070                return;
1071            }
1072            break;
1073        default:
1074            throw new IllegalStateException("Unexpected Quote value: " + quoteModePolicy);
1075        }
1076
1077        if (!quote) {
1078            // no encapsulation needed - write out the original value
1079            out.append(value, start, end);
1080            return;
1081        }
1082
1083        // we hit something that needed encapsulation
1084        out.append(quoteChar);
1085
1086        // Pick up where we left off: pos should be positioned on the first character that caused
1087        // the need for encapsulation.
1088        while (pos < end) {
1089            final char c = value.charAt(pos);
1090            if (c == quoteChar) {
1091                // write out the chunk up until this point
1092
1093                // add 1 to the length to write out the encapsulator also
1094                out.append(value, start, pos + 1);
1095                // put the next starting position on the encapsulator so we will
1096                // write it out again with the next string (effectively doubling it)
1097                start = pos;
1098            }
1099            pos++;
1100        }
1101
1102        // write the last segment
1103        out.append(value, start, pos);
1104        out.append(quoteChar);
1105    }
1106
1107    /**
1108     * Outputs the record separator.
1109     *
1110     * @param out
1111     *            where to write
1112     * @throws IOException
1113     *             If an I/O error occurs
1114     * @since 1.4
1115     */
1116    public void println(final Appendable out) throws IOException {
1117        if (getTrailingDelimiter()) {
1118            out.append(getDelimiter());
1119        }
1120        if (recordSeparator != null) {
1121            out.append(recordSeparator);
1122        }
1123    }
1124
1125    /**
1126     * Prints the given {@code values} to {@code out} as a single record of delimiter separated values followed by the
1127     * record separator.
1128     *
1129     * <p>
1130     * The values will be quoted if needed. Quotes and new-line characters will be escaped. This method adds the record
1131     * separator to the output after printing the record, so there is no need to call {@link #println(Appendable)}.
1132     * </p>
1133     *
1134     * @param out
1135     *            where to write
1136     * @param values
1137     *            values to output.
1138     * @throws IOException
1139     *             If an I/O error occurs
1140     * @since 1.4
1141     */
1142    public void printRecord(final Appendable out, final Object... values) throws IOException {
1143        for (int i = 0; i < values.length; i++) {
1144            print(values[i], out, i == 0);
1145        }
1146        println(out);
1147    }
1148
1149    @Override
1150    public String toString() {
1151        final StringBuilder sb = new StringBuilder();
1152        sb.append("Delimiter=<").append(delimiter).append('>');
1153        if (isEscapeCharacterSet()) {
1154            sb.append(' ');
1155            sb.append("Escape=<").append(escapeCharacter).append('>');
1156        }
1157        if (isQuoteCharacterSet()) {
1158            sb.append(' ');
1159            sb.append("QuoteChar=<").append(quoteCharacter).append('>');
1160        }
1161        if (isCommentMarkerSet()) {
1162            sb.append(' ');
1163            sb.append("CommentStart=<").append(commentMarker).append('>');
1164        }
1165        if (isNullStringSet()) {
1166            sb.append(' ');
1167            sb.append("NullString=<").append(nullString).append('>');
1168        }
1169        if (recordSeparator != null) {
1170            sb.append(' ');
1171            sb.append("RecordSeparator=<").append(recordSeparator).append('>');
1172        }
1173        if (getIgnoreEmptyLines()) {
1174            sb.append(" EmptyLines:ignored");
1175        }
1176        if (getIgnoreSurroundingSpaces()) {
1177            sb.append(" SurroundingSpaces:ignored");
1178        }
1179        if (getIgnoreHeaderCase()) {
1180            sb.append(" IgnoreHeaderCase:ignored");
1181        }
1182        sb.append(" SkipHeaderRecord:").append(skipHeaderRecord);
1183        if (headerComments != null) {
1184            sb.append(' ');
1185            sb.append("HeaderComments:").append(Arrays.toString(headerComments));
1186        }
1187        if (header != null) {
1188            sb.append(' ');
1189            sb.append("Header:").append(Arrays.toString(header));
1190        }
1191        return sb.toString();
1192    }
1193
1194    private String[] toStringArray(final Object[] values) {
1195        if (values == null) {
1196            return null;
1197        }
1198        final String[] strings = new String[values.length];
1199        for (int i = 0; i < values.length; i++) {
1200            final Object value = values[i];
1201            strings[i] = value == null ? null : value.toString();
1202        }
1203        return strings;
1204    }
1205
1206    private CharSequence trim(final CharSequence charSequence) {
1207        if (charSequence instanceof String) {
1208            return ((String) charSequence).trim();
1209        }
1210        final int count = charSequence.length();
1211        int len = count;
1212        int pos = 0;
1213
1214        while (pos < len && charSequence.charAt(pos) <= SP) {
1215            pos++;
1216        }
1217        while (pos < len && charSequence.charAt(len - 1) <= SP) {
1218            len--;
1219        }
1220        return pos > 0 || len < count ? charSequence.subSequence(pos, len) : charSequence;
1221    }
1222
1223    /**
1224     * Verifies the consistency of the parameters and throws an IllegalArgumentException if necessary.
1225     *
1226     * @throws IllegalArgumentException
1227     */
1228    private void validate() throws IllegalArgumentException {
1229        if (isLineBreak(delimiter)) {
1230            throw new IllegalArgumentException("The delimiter cannot be a line break");
1231        }
1232
1233        if (quoteCharacter != null && delimiter == quoteCharacter.charValue()) {
1234            throw new IllegalArgumentException(
1235                    "The quoteChar character and the delimiter cannot be the same ('" + quoteCharacter + "')");
1236        }
1237
1238        if (escapeCharacter != null && delimiter == escapeCharacter.charValue()) {
1239            throw new IllegalArgumentException(
1240                    "The escape character and the delimiter cannot be the same ('" + escapeCharacter + "')");
1241        }
1242
1243        if (commentMarker != null && delimiter == commentMarker.charValue()) {
1244            throw new IllegalArgumentException(
1245                    "The comment start character and the delimiter cannot be the same ('" + commentMarker + "')");
1246        }
1247
1248        if (quoteCharacter != null && quoteCharacter.equals(commentMarker)) {
1249            throw new IllegalArgumentException(
1250                    "The comment start character and the quoteChar cannot be the same ('" + commentMarker + "')");
1251        }
1252
1253        if (escapeCharacter != null && escapeCharacter.equals(commentMarker)) {
1254            throw new IllegalArgumentException(
1255                    "The comment start and the escape character cannot be the same ('" + commentMarker + "')");
1256        }
1257
1258        if (escapeCharacter == null && quoteMode == QuoteMode.NONE) {
1259            throw new IllegalArgumentException("No quotes mode set but no escape character is set");
1260        }
1261
1262        // validate header
1263        if (header != null) {
1264            final Set<String> dupCheck = new HashSet<>();
1265            for (final String hdr : header) {
1266                if (!dupCheck.add(hdr)) {
1267                    throw new IllegalArgumentException(
1268                            "The header contains a duplicate entry: '" + hdr + "' in " + Arrays.toString(header));
1269                }
1270            }
1271        }
1272    }
1273
1274    /**
1275     * Returns a new {@code CSVFormat} with the missing column names behavior of the format set to {@code true}
1276     *
1277     * @return A new CSVFormat that is equal to this but with the specified missing column names behavior.
1278     * @see #withAllowMissingColumnNames(boolean)
1279     * @since 1.1
1280     */
1281    public CSVFormat withAllowMissingColumnNames() {
1282        return this.withAllowMissingColumnNames(true);
1283    }
1284
1285    /**
1286     * Returns a new {@code CSVFormat} with the missing column names behavior of the format set to the given value.
1287     *
1288     * @param allowMissingColumnNames
1289     *            the missing column names behavior, {@code true} to allow missing column names in the header line,
1290     *            {@code false} to cause an {@link IllegalArgumentException} to be thrown.
1291     * @return A new CSVFormat that is equal to this but with the specified missing column names behavior.
1292     */
1293    public CSVFormat withAllowMissingColumnNames(final boolean allowMissingColumnNames) {
1294        return new CSVFormat(delimiter, quoteCharacter, quoteMode, commentMarker, escapeCharacter,
1295                ignoreSurroundingSpaces, ignoreEmptyLines, recordSeparator, nullString, headerComments, header,
1296                skipHeaderRecord, allowMissingColumnNames, ignoreHeaderCase, trim, trailingDelimiter);
1297    }
1298
1299    /**
1300     * Returns a new {@code CSVFormat} with the comment start marker of the format set to the specified character.
1301     *
1302     * Note that the comment start character is only recognized at the start of a line.
1303     *
1304     * @param commentMarker
1305     *            the comment start marker
1306     * @return A new CSVFormat that is equal to this one but with the specified character as the comment start marker
1307     * @throws IllegalArgumentException
1308     *             thrown if the specified character is a line break
1309     */
1310    public CSVFormat withCommentMarker(final char commentMarker) {
1311        return withCommentMarker(Character.valueOf(commentMarker));
1312    }
1313
1314    /**
1315     * Returns a new {@code CSVFormat} with the comment start marker of the format set to the specified character.
1316     *
1317     * Note that the comment start character is only recognized at the start of a line.
1318     *
1319     * @param commentMarker
1320     *            the comment start marker, use {@code null} to disable
1321     * @return A new CSVFormat that is equal to this one but with the specified character as the comment start marker
1322     * @throws IllegalArgumentException
1323     *             thrown if the specified character is a line break
1324     */
1325    public CSVFormat withCommentMarker(final Character commentMarker) {
1326        if (isLineBreak(commentMarker)) {
1327            throw new IllegalArgumentException("The comment start marker character cannot be a line break");
1328        }
1329        return new CSVFormat(delimiter, quoteCharacter, quoteMode, commentMarker, escapeCharacter,
1330                ignoreSurroundingSpaces, ignoreEmptyLines, recordSeparator, nullString, headerComments, header,
1331                skipHeaderRecord, allowMissingColumnNames, ignoreHeaderCase, trim, trailingDelimiter);
1332    }
1333
1334    /**
1335     * Returns a new {@code CSVFormat} with the delimiter of the format set to the specified character.
1336     *
1337     * @param delimiter
1338     *            the delimiter character
1339     * @return A new CSVFormat that is equal to this with the specified character as delimiter
1340     * @throws IllegalArgumentException
1341     *             thrown if the specified character is a line break
1342     */
1343    public CSVFormat withDelimiter(final char delimiter) {
1344        if (isLineBreak(delimiter)) {
1345            throw new IllegalArgumentException("The delimiter cannot be a line break");
1346        }
1347        return new CSVFormat(delimiter, quoteCharacter, quoteMode, commentMarker, escapeCharacter,
1348                ignoreSurroundingSpaces, ignoreEmptyLines, recordSeparator, nullString, headerComments, header,
1349                skipHeaderRecord, allowMissingColumnNames, ignoreHeaderCase, trim, trailingDelimiter);
1350    }
1351
1352    /**
1353     * Returns a new {@code CSVFormat} with the escape character of the format set to the specified character.
1354     *
1355     * @param escape
1356     *            the escape character
1357     * @return A new CSVFormat that is equal to his but with the specified character as the escape character
1358     * @throws IllegalArgumentException
1359     *             thrown if the specified character is a line break
1360     */
1361    public CSVFormat withEscape(final char escape) {
1362        return withEscape(Character.valueOf(escape));
1363    }
1364
1365    /**
1366     * Returns a new {@code CSVFormat} with the escape character of the format set to the specified character.
1367     *
1368     * @param escape
1369     *            the escape character, use {@code null} to disable
1370     * @return A new CSVFormat that is equal to this but with the specified character as the escape character
1371     * @throws IllegalArgumentException
1372     *             thrown if the specified character is a line break
1373     */
1374    public CSVFormat withEscape(final Character escape) {
1375        if (isLineBreak(escape)) {
1376            throw new IllegalArgumentException("The escape character cannot be a line break");
1377        }
1378        return new CSVFormat(delimiter, quoteCharacter, quoteMode, commentMarker, escape, ignoreSurroundingSpaces,
1379                ignoreEmptyLines, recordSeparator, nullString, headerComments, header, skipHeaderRecord,
1380                allowMissingColumnNames, ignoreHeaderCase, trim, trailingDelimiter);
1381    }
1382
1383    /**
1384     * Returns a new {@code CSVFormat} using the first record as header.
1385     *
1386     * <p>
1387     * Calling this method is equivalent to calling:
1388     * </p>
1389     *
1390     * <pre>
1391     * CSVFormat format = aFormat.withHeader().withSkipHeaderRecord();
1392     * </pre>
1393     *
1394     * @return A new CSVFormat that is equal to this but using the first record as header.
1395     * @see #withSkipHeaderRecord(boolean)
1396     * @see #withHeader(String...)
1397     * @since 1.3
1398     */
1399    public CSVFormat withFirstRecordAsHeader() {
1400        return withHeader().withSkipHeaderRecord();
1401    }
1402
1403    /**
1404     * Returns a new {@code CSVFormat} with the header of the format defined by the enum class.
1405     *
1406     * <p>
1407     * Example:
1408     * </p>
1409     * <pre>
1410     * public enum Header {
1411     *     Name, Email, Phone
1412     * }
1413     *
1414     * CSVFormat format = aformat.withHeader(Header.class);
1415     * </pre>
1416     * <p>
1417     * The header is also used by the {@link CSVPrinter}.
1418     * </p>
1419     *
1420     * @param headerEnum
1421     *            the enum defining the header, {@code null} if disabled, empty if parsed automatically, user specified
1422     *            otherwise.
1423     *
1424     * @return A new CSVFormat that is equal to this but with the specified header
1425     * @see #withHeader(String...)
1426     * @see #withSkipHeaderRecord(boolean)
1427     * @since 1.3
1428     */
1429    public CSVFormat withHeader(final Class<? extends Enum<?>> headerEnum) {
1430        String[] header = null;
1431        if (headerEnum != null) {
1432            final Enum<?>[] enumValues = headerEnum.getEnumConstants();
1433            header = new String[enumValues.length];
1434            for (int i = 0; i < enumValues.length; i++) {
1435                header[i] = enumValues[i].name();
1436            }
1437        }
1438        return withHeader(header);
1439    }
1440
1441    /**
1442     * Returns a new {@code CSVFormat} with the header of the format set from the result set metadata. The header can
1443     * either be parsed automatically from the input file with:
1444     *
1445     * <pre>
1446     * CSVFormat format = aformat.withHeader();
1447     * </pre>
1448     *
1449     * or specified manually with:
1450     *
1451     * <pre>
1452     * CSVFormat format = aformat.withHeader(resultSet);
1453     * </pre>
1454     * <p>
1455     * The header is also used by the {@link CSVPrinter}.
1456     * </p>
1457     *
1458     * @param resultSet
1459     *            the resultSet for the header, {@code null} if disabled, empty if parsed automatically, user specified
1460     *            otherwise.
1461     *
1462     * @return A new CSVFormat that is equal to this but with the specified header
1463     * @throws SQLException
1464     *             SQLException if a database access error occurs or this method is called on a closed result set.
1465     * @since 1.1
1466     */
1467    public CSVFormat withHeader(final ResultSet resultSet) throws SQLException {
1468        return withHeader(resultSet != null ? resultSet.getMetaData() : null);
1469    }
1470
1471    /**
1472     * Returns a new {@code CSVFormat} with the header of the format set from the result set metadata. The header can
1473     * either be parsed automatically from the input file with:
1474     *
1475     * <pre>
1476     * CSVFormat format = aformat.withHeader();
1477     * </pre>
1478     *
1479     * or specified manually with:
1480     *
1481     * <pre>
1482     * CSVFormat format = aformat.withHeader(metaData);
1483     * </pre>
1484     * <p>
1485     * The header is also used by the {@link CSVPrinter}.
1486     * </p>
1487     *
1488     * @param metaData
1489     *            the metaData for the header, {@code null} if disabled, empty if parsed automatically, user specified
1490     *            otherwise.
1491     *
1492     * @return A new CSVFormat that is equal to this but with the specified header
1493     * @throws SQLException
1494     *             SQLException if a database access error occurs or this method is called on a closed result set.
1495     * @since 1.1
1496     */
1497    public CSVFormat withHeader(final ResultSetMetaData metaData) throws SQLException {
1498        String[] labels = null;
1499        if (metaData != null) {
1500            final int columnCount = metaData.getColumnCount();
1501            labels = new String[columnCount];
1502            for (int i = 0; i < columnCount; i++) {
1503                labels[i] = metaData.getColumnLabel(i + 1);
1504            }
1505        }
1506        return withHeader(labels);
1507    }
1508
1509    /**
1510     * Returns a new {@code CSVFormat} with the header of the format set to the given values. The header can either be
1511     * parsed automatically from the input file with:
1512     *
1513     * <pre>
1514     * CSVFormat format = aformat.withHeader();
1515     * </pre>
1516     *
1517     * or specified manually with:
1518     *
1519     * <pre>
1520     * CSVFormat format = aformat.withHeader(&quot;name&quot;, &quot;email&quot;, &quot;phone&quot;);
1521     * </pre>
1522     * <p>
1523     * The header is also used by the {@link CSVPrinter}.
1524     * </p>
1525     *
1526     * @param header
1527     *            the header, {@code null} if disabled, empty if parsed automatically, user specified otherwise.
1528     *
1529     * @return A new CSVFormat that is equal to this but with the specified header
1530     * @see #withSkipHeaderRecord(boolean)
1531     */
1532    public CSVFormat withHeader(final String... header) {
1533        return new CSVFormat(delimiter, quoteCharacter, quoteMode, commentMarker, escapeCharacter,
1534                ignoreSurroundingSpaces, ignoreEmptyLines, recordSeparator, nullString, headerComments, header,
1535                skipHeaderRecord, allowMissingColumnNames, ignoreHeaderCase, trim, trailingDelimiter);
1536    }
1537
1538    /**
1539     * Returns a new {@code CSVFormat} with the header comments of the format set to the given values. The comments will
1540     * be printed first, before the headers. This setting is ignored by the parser.
1541     *
1542     * <pre>
1543     * CSVFormat format = aformat.withHeaderComments(&quot;Generated by Apache Commons CSV 1.1.&quot;, new Date());
1544     * </pre>
1545     *
1546     * @param headerComments
1547     *            the headerComments which will be printed by the Printer before the actual CSV data.
1548     *
1549     * @return A new CSVFormat that is equal to this but with the specified header
1550     * @see #withSkipHeaderRecord(boolean)
1551     * @since 1.1
1552     */
1553    public CSVFormat withHeaderComments(final Object... headerComments) {
1554        return new CSVFormat(delimiter, quoteCharacter, quoteMode, commentMarker, escapeCharacter,
1555                ignoreSurroundingSpaces, ignoreEmptyLines, recordSeparator, nullString, headerComments, header,
1556                skipHeaderRecord, allowMissingColumnNames, ignoreHeaderCase, trim, trailingDelimiter);
1557    }
1558
1559    /**
1560     * Returns a new {@code CSVFormat} with the empty line skipping behavior of the format set to {@code true}.
1561     *
1562     * @return A new CSVFormat that is equal to this but with the specified empty line skipping behavior.
1563     * @since {@link #withIgnoreEmptyLines(boolean)}
1564     * @since 1.1
1565     */
1566    public CSVFormat withIgnoreEmptyLines() {
1567        return this.withIgnoreEmptyLines(true);
1568    }
1569
1570    /**
1571     * Returns a new {@code CSVFormat} with the empty line skipping behavior of the format set to the given value.
1572     *
1573     * @param ignoreEmptyLines
1574     *            the empty line skipping behavior, {@code true} to ignore the empty lines between the records,
1575     *            {@code false} to translate empty lines to empty records.
1576     * @return A new CSVFormat that is equal to this but with the specified empty line skipping behavior.
1577     */
1578    public CSVFormat withIgnoreEmptyLines(final boolean ignoreEmptyLines) {
1579        return new CSVFormat(delimiter, quoteCharacter, quoteMode, commentMarker, escapeCharacter,
1580                ignoreSurroundingSpaces, ignoreEmptyLines, recordSeparator, nullString, headerComments, header,
1581                skipHeaderRecord, allowMissingColumnNames, ignoreHeaderCase, trim, trailingDelimiter);
1582    }
1583
1584    /**
1585     * Returns a new {@code CSVFormat} with the header ignore case behavior set to {@code true}.
1586     *
1587     * @return A new CSVFormat that will ignore case header name.
1588     * @see #withIgnoreHeaderCase(boolean)
1589     * @since 1.3
1590     */
1591    public CSVFormat withIgnoreHeaderCase() {
1592        return this.withIgnoreHeaderCase(true);
1593    }
1594
1595    /**
1596     * Returns a new {@code CSVFormat} with whether header names should be accessed ignoring case.
1597     *
1598     * @param ignoreHeaderCase
1599     *            the case mapping behavior, {@code true} to access name/values, {@code false} to leave the mapping as
1600     *            is.
1601     * @return A new CSVFormat that will ignore case header name if specified as {@code true}
1602     * @since 1.3
1603     */
1604    public CSVFormat withIgnoreHeaderCase(final boolean ignoreHeaderCase) {
1605        return new CSVFormat(delimiter, quoteCharacter, quoteMode, commentMarker, escapeCharacter,
1606                ignoreSurroundingSpaces, ignoreEmptyLines, recordSeparator, nullString, headerComments, header,
1607                skipHeaderRecord, allowMissingColumnNames, ignoreHeaderCase, trim, trailingDelimiter);
1608    }
1609
1610    /**
1611     * Returns a new {@code CSVFormat} with the trimming behavior of the format set to {@code true}.
1612     *
1613     * @return A new CSVFormat that is equal to this but with the specified trimming behavior.
1614     * @see #withIgnoreSurroundingSpaces(boolean)
1615     * @since 1.1
1616     */
1617    public CSVFormat withIgnoreSurroundingSpaces() {
1618        return this.withIgnoreSurroundingSpaces(true);
1619    }
1620
1621    /**
1622     * Returns a new {@code CSVFormat} with the trimming behavior of the format set to the given value.
1623     *
1624     * @param ignoreSurroundingSpaces
1625     *            the trimming behavior, {@code true} to remove the surrounding spaces, {@code false} to leave the
1626     *            spaces as is.
1627     * @return A new CSVFormat that is equal to this but with the specified trimming behavior.
1628     */
1629    public CSVFormat withIgnoreSurroundingSpaces(final boolean ignoreSurroundingSpaces) {
1630        return new CSVFormat(delimiter, quoteCharacter, quoteMode, commentMarker, escapeCharacter,
1631                ignoreSurroundingSpaces, ignoreEmptyLines, recordSeparator, nullString, headerComments, header,
1632                skipHeaderRecord, allowMissingColumnNames, ignoreHeaderCase, trim, trailingDelimiter);
1633    }
1634
1635    /**
1636     * Returns a new {@code CSVFormat} with conversions to and from null for strings on input and output.
1637     * <ul>
1638     * <li><strong>Reading:</strong> Converts strings equal to the given {@code nullString} to {@code null} when reading
1639     * records.</li>
1640     * <li><strong>Writing:</strong> Writes {@code null} as the given {@code nullString} when writing records.</li>
1641     * </ul>
1642     *
1643     * @param nullString
1644     *            the String to convert to and from {@code null}. No substitution occurs if {@code null}
1645     *
1646     * @return A new CSVFormat that is equal to this but with the specified null conversion string.
1647     */
1648    public CSVFormat withNullString(final String nullString) {
1649        return new CSVFormat(delimiter, quoteCharacter, quoteMode, commentMarker, escapeCharacter,
1650                ignoreSurroundingSpaces, ignoreEmptyLines, recordSeparator, nullString, headerComments, header,
1651                skipHeaderRecord, allowMissingColumnNames, ignoreHeaderCase, trim, trailingDelimiter);
1652    }
1653
1654    /**
1655     * Returns a new {@code CSVFormat} with the quoteChar of the format set to the specified character.
1656     *
1657     * @param quoteChar
1658     *            the quoteChar character
1659     * @return A new CSVFormat that is equal to this but with the specified character as quoteChar
1660     * @throws IllegalArgumentException
1661     *             thrown if the specified character is a line break
1662     */
1663    public CSVFormat withQuote(final char quoteChar) {
1664        return withQuote(Character.valueOf(quoteChar));
1665    }
1666
1667    /**
1668     * Returns a new {@code CSVFormat} with the quoteChar of the format set to the specified character.
1669     *
1670     * @param quoteChar
1671     *            the quoteChar character, use {@code null} to disable
1672     * @return A new CSVFormat that is equal to this but with the specified character as quoteChar
1673     * @throws IllegalArgumentException
1674     *             thrown if the specified character is a line break
1675     */
1676    public CSVFormat withQuote(final Character quoteChar) {
1677        if (isLineBreak(quoteChar)) {
1678            throw new IllegalArgumentException("The quoteChar cannot be a line break");
1679        }
1680        return new CSVFormat(delimiter, quoteChar, quoteMode, commentMarker, escapeCharacter, ignoreSurroundingSpaces,
1681                ignoreEmptyLines, recordSeparator, nullString, headerComments, header, skipHeaderRecord,
1682                allowMissingColumnNames, ignoreHeaderCase, trim, trailingDelimiter);
1683    }
1684
1685    /**
1686     * Returns a new {@code CSVFormat} with the output quote policy of the format set to the specified value.
1687     *
1688     * @param quoteModePolicy
1689     *            the quote policy to use for output.
1690     *
1691     * @return A new CSVFormat that is equal to this but with the specified quote policy
1692     */
1693    public CSVFormat withQuoteMode(final QuoteMode quoteModePolicy) {
1694        return new CSVFormat(delimiter, quoteCharacter, quoteModePolicy, commentMarker, escapeCharacter,
1695                ignoreSurroundingSpaces, ignoreEmptyLines, recordSeparator, nullString, headerComments, header,
1696                skipHeaderRecord, allowMissingColumnNames, ignoreHeaderCase, trim, trailingDelimiter);
1697    }
1698
1699    /**
1700     * Returns a new {@code CSVFormat} with the record separator of the format set to the specified character.
1701     *
1702     * <p>
1703     * <strong>Note:</strong> This setting is only used during printing and does not affect parsing. Parsing currently
1704     * only works for inputs with '\n', '\r' and "\r\n"
1705     * </p>
1706     *
1707     * @param recordSeparator
1708     *            the record separator to use for output.
1709     *
1710     * @return A new CSVFormat that is equal to this but with the the specified output record separator
1711     */
1712    public CSVFormat withRecordSeparator(final char recordSeparator) {
1713        return withRecordSeparator(String.valueOf(recordSeparator));
1714    }
1715
1716    /**
1717     * Returns a new {@code CSVFormat} with the record separator of the format set to the specified String.
1718     *
1719     * <p>
1720     * <strong>Note:</strong> This setting is only used during printing and does not affect parsing. Parsing currently
1721     * only works for inputs with '\n', '\r' and "\r\n"
1722     * </p>
1723     *
1724     * @param recordSeparator
1725     *            the record separator to use for output.
1726     *
1727     * @return A new CSVFormat that is equal to this but with the the specified output record separator
1728     * @throws IllegalArgumentException
1729     *             if recordSeparator is none of CR, LF or CRLF
1730     */
1731    public CSVFormat withRecordSeparator(final String recordSeparator) {
1732        return new CSVFormat(delimiter, quoteCharacter, quoteMode, commentMarker, escapeCharacter,
1733                ignoreSurroundingSpaces, ignoreEmptyLines, recordSeparator, nullString, headerComments, header,
1734                skipHeaderRecord, allowMissingColumnNames, ignoreHeaderCase, trim, trailingDelimiter);
1735    }
1736
1737    /**
1738     * Returns a new {@code CSVFormat} with skipping the header record set to {@code true}.
1739     *
1740     * @return A new CSVFormat that is equal to this but with the the specified skipHeaderRecord setting.
1741     * @see #withSkipHeaderRecord(boolean)
1742     * @see #withHeader(String...)
1743     * @since 1.1
1744     */
1745    public CSVFormat withSkipHeaderRecord() {
1746        return this.withSkipHeaderRecord(true);
1747    }
1748
1749    /**
1750     * Returns a new {@code CSVFormat} with whether to skip the header record.
1751     *
1752     * @param skipHeaderRecord
1753     *            whether to skip the header record.
1754     *
1755     * @return A new CSVFormat that is equal to this but with the the specified skipHeaderRecord setting.
1756     * @see #withHeader(String...)
1757     */
1758    public CSVFormat withSkipHeaderRecord(final boolean skipHeaderRecord) {
1759        return new CSVFormat(delimiter, quoteCharacter, quoteMode, commentMarker, escapeCharacter,
1760                ignoreSurroundingSpaces, ignoreEmptyLines, recordSeparator, nullString, headerComments, header,
1761                skipHeaderRecord, allowMissingColumnNames, ignoreHeaderCase, trim, trailingDelimiter);
1762    }
1763
1764    /**
1765     * Returns a new {@code CSVFormat} to add a trailing delimiter.
1766     *
1767     * @return A new CSVFormat that is equal to this but with the trailing delimiter setting.
1768     * @since 1.3
1769     */
1770    public CSVFormat withTrailingDelimiter() {
1771        return withTrailingDelimiter(true);
1772    }
1773
1774    /**
1775     * Returns a new {@code CSVFormat} with whether to add a trailing delimiter.
1776     *
1777     * @param trailingDelimiter
1778     *            whether to add a trailing delimiter.
1779     *
1780     * @return A new CSVFormat that is equal to this but with the specified trailing delimiter setting.
1781     * @since 1.3
1782     */
1783    public CSVFormat withTrailingDelimiter(final boolean trailingDelimiter) {
1784        return new CSVFormat(delimiter, quoteCharacter, quoteMode, commentMarker, escapeCharacter,
1785                ignoreSurroundingSpaces, ignoreEmptyLines, recordSeparator, nullString, headerComments, header,
1786                skipHeaderRecord, allowMissingColumnNames, ignoreHeaderCase, trim, trailingDelimiter);
1787    }
1788
1789    /**
1790     * Returns a new {@code CSVFormat} to trim leading and trailing blanks.
1791     *
1792     * @return A new CSVFormat that is equal to this but with the trim setting on.
1793     * @since 1.3
1794     */
1795    public CSVFormat withTrim() {
1796        return withTrim(true);
1797    }
1798
1799    /**
1800     * Returns a new {@code CSVFormat} with whether to trim leading and trailing blanks.
1801     *
1802     * @param trim
1803     *            whether to trim leading and trailing blanks.
1804     *
1805     * @return A new CSVFormat that is equal to this but with the specified trim setting.
1806     * @since 1.3
1807     */
1808    public CSVFormat withTrim(final boolean trim) {
1809        return new CSVFormat(delimiter, quoteCharacter, quoteMode, commentMarker, escapeCharacter,
1810                ignoreSurroundingSpaces, ignoreEmptyLines, recordSeparator, nullString, headerComments, header,
1811                skipHeaderRecord, allowMissingColumnNames, ignoreHeaderCase, trim, trailingDelimiter);
1812    }
1813}