0

We have a simple string:

let str = "\"abc\", \"def\",\"ghi\" , 123.4, 567, \"qwe,rty\""

If we do this:

let parsedCSV = str
            .components(separatedBy: .newlines)
            .filter { !$0.isEmpty }
            .map { $0.components(separatedBy: ",") }
            .map { $0.map { $0.trimmingCharacters(in: .whitespaces) } }
print(parsedCSV)

we get this:

[["\"abc\"", "\"def\"", "\"ghi\"", "123.4", "567", "\"qwe", "rty\""]]

Is there a simple solution (using functional programming) not to split the last element \"qwe,rty\", because we know that it's one whole thing?

4
  • That's not so simple. You need context to handle the " and in general it's easier to just go loop by the columns one by one. Commented Jun 28, 2018 at 14:43
  • 2
    I would recommend to use a library, e.g. github.com/naoty/SwiftCSV Commented Jun 28, 2018 at 14:45
  • Non-trivial CSV data is a lot more complicated to process than most people realize. It can't be parsed with simple string manipulations. Use (or write) a proper CSV parsing library. Commented Jun 28, 2018 at 15:53
  • SwiftCSV is not supported by swift 4... Commented Jun 28, 2018 at 16:14

3 Answers 3

1

Well this is a hack, it works for this case.... not very simple solution for complex issue ...

let str = "\"abc\", \"def\",\"ghi\" , 123.4, 567, \"qwe,rty\""

let parsedCSV = str
    .components(separatedBy: .newlines)
    .filter { !$0.isEmpty }
    .map { $0.components(separatedBy: ",") }
    .map { $0.map { $0.trimmingCharacters(in: .whitespaces) } }.reduce([]) { (result, items) -> [String] in
        var goodItems = items.filter{ $0.components(separatedBy: "\"").count == 3 ||  $0.components(separatedBy: "\"").count == 1}
        let arr = items.filter{ $0.components(separatedBy: "\"").count == 2}
        var join:[String] = []
        for x in 0..<arr.count {
            let j = x + 1
            if j < arr.count {
                join = [arr[x] + "," + arr[j]]
            }
        }
        goodItems.append(contentsOf: join)
        return goodItems
}


print(parsedCSV)

print out

["\"abc\"", "\"def\"", "\"ghi\"", "123.4", "567", "\"qwe,rty\""]

Sign up to request clarification or add additional context in comments.

1 Comment

Yes, that's the way it should be! Still it's not perfect, because if we add something at the end of the str - the order of the output string will be changed.
0

I've done that.

let str = "_, * ,, \"abc\",  000, def, ghi , 123.4,,  567,  \"qwe,rty,eur\", jkl"
    let separator = ","
    let parsedCSV = str
        .components(separatedBy: .newlines)
        .filter { !$0.isEmpty }
        .map { $0.components(separatedBy: separator).map { $0.trimmingCharacters(in: .whitespaces) } }
        .reduce([]) { (result, items) -> [String] in
            var result: [String] = []
            for item in items {
                guard let last = result.last, last.components(separatedBy: "\"").count % 2 == 0 else {
                    result.append(item)
                    continue
                }
                result.removeLast()
                let lastModified = record + separator + item
                result.append(lastModified)

            }
            return result
    }.map { $0.trimmingCharacters(in: CharacterSet(charactersIn: "\"")) }
    print(parsedCSV)

["_", "*", "", "abc", "000", "def", "ghi", "123.4", "", "567", "qwe,rty,eur", "jkl"]

Comments

0

If you do not mind using Regular Expression, you can write something like this:

let str = "_, * ,, \"abc\",  000, def, ghi , 123.4,,  567,  \"qwe,rty,eur\", jkl"

let pattern = "((?:[^\",]|\"[^\"]*\")*)(?:,|$)"
let regex = try! NSRegularExpression(pattern: pattern)

let parsedCSV = regex.matches(in: str, options: .anchored, range: NSRange(0..<str.utf16.count))
    .map {$0.range(at: 1)}
    .filter {$0.location != NSNotFound && $0.location < str.utf16.count}
    .map {String(str[Range<String.Index>($0, in: str)!]).trimmingCharacters(in: .whitespaces)}
    .map {$0.trimmingCharacters(in: CharacterSet(charactersIn: "\""))}
print(parsedCSV) //->["_", "*", "", "abc", "000", "def", "ghi", "123.4", "", "567", "qwe,rty,eur", "jkl"]

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.