swift: working with string


swift: working with string



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?


"qwe,rty"





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.
– Sulthan
Jun 28 at 14:43


"





I would recommend to use a library, e.g. github.com/naoty/SwiftCSV
– Sulthan
Jun 28 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.
– rmaddy
Jun 28 at 15:53





SwiftCSV is not supported by swift 4...
– Anton
Jun 28 at 16:14




3 Answers
3



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""]





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.
– Anton
Jun 29 at 4:16



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"]



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"]






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Popular posts from this blog

How to input without newline? (Python)

C++ thread error: no type named ‘type’ MINGW

Analog for TagView in flutter