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