Skip to content

Commit 3678d3f

Browse files
committed
Allow CSVReader escapingScalar to be disabled
1 parent 124903b commit 3678d3f

2 files changed

Lines changed: 7 additions & 6 deletions

File tree

Sources/Active/Reader/Reader.swift

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -169,8 +169,8 @@ extension CSVReader {
169169
}
170170

171171
// 4. If the unicode scalar retrieved is a double quote, an escaped field is awaiting for parsing.
172-
if scalar == self.settings.escapingScalar {
173-
let field = try self.parseEscapedField(rowIndex: rowIndex)
172+
if let escapingScalar = self.settings.escapingScalar, scalar == escapingScalar {
173+
let field = try self.parseEscapedField(rowIndex: rowIndex, escaping: escapingScalar)
174174
result.append(field.value)
175175
if field.isAtEnd { break loop }
176176
// 5. If the field delimiter is encountered, an implicit empty field has been defined.
@@ -233,21 +233,22 @@ extension CSVReader {
233233
///
234234
/// When this function is executed, the quote opening the "escaped field" has already been read.
235235
/// - parameter rowIndex: The index of the row being parsed.
236+
/// - parameter escapingScalar: The unicode scalar escaping character to use.
236237
/// - throws: `CSVError<CSVReader>` exclusively.
237238
/// - returns: The parsed field and whether the row/file ending characters have been found.
238-
private func parseEscapedField(rowIndex: Int) throws -> (value: String, isAtEnd: Bool) {
239+
private func parseEscapedField(rowIndex: Int, escaping escapingScalar: Unicode.Scalar) throws -> (value: String, isAtEnd: Bool) {
239240
var field: String.UnicodeScalarView = .init()
240241
var reachedRowsEnd = false
241242

242243
fieldLoop: while true {
243244
// 1. Retrieve an scalar (if not there, it means EOF). This case is not allowed without closing the escaping field first.
244245
guard let scalar = try self.buffer.next() ?? self.decoder() else { throw Error.invalidEOF(rowIndex: rowIndex) }
245246
// 2. If the retrieved scalar is not a quote (i.e. "), just store it and continue parsing.
246-
guard scalar == self.settings.escapingScalar else { field.append(scalar); continue fieldLoop }
247+
guard scalar == escapingScalar else { field.append(scalar); continue fieldLoop }
247248
// 3. If the retrieved scalar was a quote, retrieve the following scalar and check if it is EOF. If so, the field has finished and also the row and the file.
248249
guard var followingScalar = try self.buffer.next() ?? self.decoder() else { reachedRowsEnd = true; break fieldLoop }
249250
// 4. If the second retrieved scalar is another quote, the data is escaping a single quote scalar (quotes are escaped with other quotes).
250-
guard followingScalar != self.settings.escapingScalar else { field.append(self.settings.escapingScalar); continue fieldLoop }
251+
guard followingScalar != escapingScalar else { field.append(escapingScalar); continue fieldLoop }
251252
// 5. Once this point is reached, the field has been properly escaped.
252253
if !self.settings.trimCharacters.isEmpty {
253254
// 6. Trim any character after the quote if necessary.

Sources/Active/Reader/ReaderConfiguration.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ extension CSVReader {
3838
/// The characters set to be trimmed at the beginning and ending of each field.
3939
let trimCharacters: CharacterSet
4040
/// The unicode scalar used as encapsulator and escaping character (when printed two times).
41-
let escapingScalar: Unicode.Scalar = "\""
41+
let escapingScalar: Unicode.Scalar? = "\""
4242

4343
/// Creates the inmutable reader settings from the user provided configuration values.
4444
/// - parameter configuration: The configuration values provided by the API user.

0 commit comments

Comments
 (0)