-
Notifications
You must be signed in to change notification settings - Fork 194
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* add CSV.guessedDelimiter(string:) helper * add delimiter-guessing initializer * add CSV.Delimiter enum * use CSV.Delimiter for initializers * re-group initializers * expand README to mention delimiters and talk a bit about the API
- Loading branch information
1 parent
38fa397
commit 7461683
Showing
10 changed files
with
332 additions
and
83 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
// | ||
// CSV+DelimiterGuessing.swift | ||
// SwiftCSV | ||
// | ||
// Created by Christian Tietze on 21.12.21. | ||
// Copyright © 2021 SwiftCSV. All rights reserved. | ||
// | ||
|
||
import Foundation | ||
|
||
extension CSV { | ||
public static let recognizedDelimiters: [Delimiter] = [.comma, .tab, .semicolon] | ||
|
||
/// - Returns: Delimiter between cells based on the first line in the CSV. Falls back to `.comma`. | ||
public static func guessedDelimiter(string: String) -> Delimiter { | ||
let recognizedDelimiterCharacters = recognizedDelimiters.map(\.rawValue) | ||
|
||
// Trim newline and spaces, but keep tabs (as delimiters) | ||
var trimmedCharacters = CharacterSet.whitespacesAndNewlines | ||
trimmedCharacters.remove("\t") | ||
let line = string.trimmingCharacters(in: trimmedCharacters).firstLine | ||
|
||
var index = line.startIndex | ||
while index < line.endIndex { | ||
let character = line[index] | ||
switch character { | ||
case "\"": | ||
// When encountering an open quote, skip to the closing counterpart. | ||
// If none is found, skip to end of line. | ||
|
||
// 1) Advance one character to skip the quote | ||
index = line.index(after: index) | ||
|
||
// 2) Look for the closing quote and move current position after it | ||
if index < line.endIndex, | ||
let closingQuoteInddex = line[index...].firstIndex(of: character) { | ||
index = line.index(after: closingQuoteInddex) | ||
} else { | ||
index = line.endIndex | ||
} | ||
case _ where recognizedDelimiterCharacters.contains(character): | ||
return Delimiter(rawValue: character) | ||
default: | ||
index = line.index(after: index) | ||
} | ||
} | ||
|
||
// Fallback value | ||
return .comma | ||
} | ||
} |
Oops, something went wrong.