diff --git a/README.md b/README.md
index 1098214..d7fe7af 100644
--- a/README.md
+++ b/README.md
@@ -163,18 +163,19 @@ val tsvReader = csvReader {
}
```
-| Option | default value | description |
-|--------------------------------|---------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| logger | _no-op_ | Logger instance for logging debug information at runtime. |
-| charset | `UTF-8` | Charset encoding. The value must be supported by [java.nio.charset.Charset](https://docs.oracle.com/javase/8/docs/api/java/nio/charset/Charset.html). |
-| quoteChar | `"` | Character used to quote fields. |
-| delimiter | `,` | Character used as delimiter between each field.
Use `"\t"` if reading TSV file. |
-| escapeChar | `"` | Character to escape quote inside field string.
Normally, you don't have to change this option.
See detail comment on [ICsvReaderContext](src/commonMain/kotlin/com/github/doyaaaaaken/kotlincsv/dsl/context/CsvReaderContext.kt). |
-| skipEmptyLine | `false` | Whether to skip or error out on empty lines. |
-| autoRenameDuplicateHeaders | `false` | Whether to auto rename duplicate headers or throw an exception. |
-| ~~skipMissMatchedRow~~ | `false` | Deprecated. Replace with appropriate values in `excessFieldsRowBehaviour` and `insufficientFieldsRowBehaviour`, e.g. both set to `IGNORE`. ~~Whether to skip an invalid row. If `ignoreExcessCols` is true, only rows with less than the expected number of columns will be skipped.~~ |
-| excessFieldsRowBehaviour | `ERROR` | Behaviour to use when a row has more fields (columns) than expected. `ERROR` (default), `IGNORE` (skip the row) or `TRIM` (remove the excess fields at the end of the row to match the expected number of fields). |
-| insufficientFieldsRowBehaviour | `ERROR` | Behaviour to use when a row has fewer fields (columns) than expected. `ERROR` (default), `IGNORE` (skip the row) or `EMPTY_STRING` (replace missing fields with an empty string). |
+| Option | default value | description |
+|--------------------------------|---------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| logger | _no-op_ | Logger instance for logging debug information at runtime. |
+| charset | `UTF-8` | Charset encoding. The value must be supported by [java.nio.charset.Charset](https://docs.oracle.com/javase/8/docs/api/java/nio/charset/Charset.html). |
+| quoteChar | `"` | Character used to quote fields. |
+| delimiter | `,` | Character used as delimiter between each field.
Use `"\t"` if reading TSV file. |
+| escapeChar | `"` | Character to escape quote inside field string.
Normally, you don't have to change this option.
See detail comment on [ICsvReaderContext](src/commonMain/kotlin/com/github/doyaaaaaken/kotlincsv/dsl/context/CsvReaderContext.kt). |
+| skipEmptyLine | `false` | Whether to skip or error out on empty lines. |
+| autoRenameDuplicateHeaders | `false` | Whether to auto rename duplicate headers or throw an exception. |
+| ~~skipMissMatchedRow~~ | `false` | Deprecated. Replace with appropriate values in `excessFieldsRowBehaviour` and `insufficientFieldsRowBehaviour`, e.g. both set to `IGNORE`. ~~Whether to skip an invalid row. If `ignoreExcessCols` is true, only rows with less than the expected number of columns will be skipped.~~ |
+| excessFieldsRowBehaviour | `ERROR` | Behaviour to use when a row has more fields (columns) than expected. `ERROR` (default), `IGNORE` (skip the row) or `TRIM` (remove the excess fields at the end of the row to match the expected number of fields). |
+| insufficientFieldsRowBehaviour | `ERROR` | Behaviour to use when a row has fewer fields (columns) than expected. `ERROR` (default), `IGNORE` (skip the row) or `EMPTY_STRING` (replace missing fields with an empty string). |
+| withFieldAsNull | `NEITHER` | Behaviour to handle two empty separators or quotes as null. `NEITHER` (default, two sequential separators or quotes are handled as empty string), `EMPTY_SEPARATORS` (two sequential separators are null), `EMPTY_QUOTES` (two sequential quotes are null) or `BOTH` (two sequential separators and two sequential quotes are null). |
### CSV Write examples
diff --git a/src/commonMain/kotlin/com/github/doyaaaaaken/kotlincsv/client/CsvFileReader.kt b/src/commonMain/kotlin/com/github/doyaaaaaken/kotlincsv/client/CsvFileReader.kt
index 3577ab0..1bc273f 100644
--- a/src/commonMain/kotlin/com/github/doyaaaaaken/kotlincsv/client/CsvFileReader.kt
+++ b/src/commonMain/kotlin/com/github/doyaaaaaken/kotlincsv/client/CsvFileReader.kt
@@ -1,13 +1,15 @@
package com.github.doyaaaaaken.kotlincsv.client
+import com.github.doyaaaaaken.kotlincsv.dsl.context.CSVReaderNullFieldIndicator
import com.github.doyaaaaaken.kotlincsv.dsl.context.CsvReaderContext
import com.github.doyaaaaaken.kotlincsv.dsl.context.ExcessFieldsRowBehaviour
import com.github.doyaaaaaken.kotlincsv.dsl.context.InsufficientFieldsRowBehaviour
import com.github.doyaaaaaken.kotlincsv.parser.CsvParser
+import com.github.doyaaaaaken.kotlincsv.parser.ParserNullFieldIndicator
import com.github.doyaaaaaken.kotlincsv.util.CSVAutoRenameFailedException
import com.github.doyaaaaaken.kotlincsv.util.CSVFieldNumDifferentException
-import com.github.doyaaaaaken.kotlincsv.util.logger.Logger
import com.github.doyaaaaaken.kotlincsv.util.MalformedCSVException
+import com.github.doyaaaaaken.kotlincsv.util.logger.Logger
/**
* CSV Reader class, which controls file I/O flow.
@@ -23,7 +25,7 @@ class CsvFileReader internal constructor(
private val reader = BufferedLineReader(reader)
private var rowNum = 0L
- private val parser = CsvParser(ctx.quoteChar, ctx.delimiter, ctx.escapeChar)
+ private val parser = CsvParser(ctx.quoteChar, ctx.delimiter, ctx.escapeChar, ctx.withFieldAsNull.toParserNullFieldIndicator())
/**
* read next csv row
@@ -33,14 +35,14 @@ class CsvFileReader internal constructor(
* or return null, if all line are already read.
*/
@Deprecated("We are considering making it a private method. If you have feedback, please comment on Issue #100.")
- fun readNext(): List? {
+ fun readNext(): List? {
return readUntilNextCsvRow("")
}
/**
* read all csv rows as Sequence
*/
- fun readAllAsSequence(fieldsNum: Int? = null): Sequence> {
+ fun readAllAsSequence(fieldsNum: Int? = null): Sequence> {
var expectedNumFieldsInRow: Int? = fieldsNum
return generateSequence {
@Suppress("DEPRECATION") readNext()
@@ -76,7 +78,7 @@ class CsvFileReader internal constructor(
private fun skipMismatchedRow(
idx: Int,
- row: List,
+ row: List,
numFieldsInRow: Int
): Nothing? {
logger.info("skip miss matched row. [csv row num = ${idx + 1}, fields num = ${row.size}, fields num of first row = $numFieldsInRow]")
@@ -86,9 +88,9 @@ class CsvFileReader internal constructor(
/**
* read all csv rows as Sequence with header information
*/
- fun readAllWithHeaderAsSequence(): Sequence