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