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