Работа с String


#1

Возьмем простую строку:

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) } }
print(parsedCSV)

И получим:

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

Есть ли какой-то простой способ (используя функциональное прогр-ие) не разделять по запятой последнюю строку в массиве \"qwe,rty\" , потому что мы понимаем, что это одно целое?


#2

Как вариант, сделать формат вашей строки строгим, что бы после каждой разделяющей запятой шел пробел, тогда разделять данные можно по ", ". В таком случае запятая внутри данных, не должна содержать пробела после себя.

Либо, еще один вариант, кодировать запятую в данных. Перед выводом данных, декодировать обратно.


#3

От меня формат не зависит, какой есть - такой есть. Здесь я приводил простой пример, по факту у меня csv файл.

Клдировать каким образом? Заменять запятые на какой-нибудь спецсимвол?


#4

Если вам приходит csv файл, используйте любую библиотеку для работы с csv.

Если вам приходит именно строка и нету возможности менять формат данных на сервере, тогда нужно думать как выйти из этой ситуации.


#5

Вот что у меня получается:

let str = "\"abc\",  \"def\",\"ghi\" , 123.4,  567,  \"qwe,rty\", jkl"
        
let parsedCSV = str
            .components(separatedBy: .newlines)
            .filter { !$0.isEmpty }
            .map { $0.components(separatedBy: ",") }
            .map { $0.map { $0.trimmingCharacters(in: .whitespaces) } }
            .map { line in line.enumerated().map { (offset, element) -> String in
                if offset > 0, line[offset - 1].first == "\"", line[offset - 1].last != "\"", line[offset].last == "\"" {
                    return [line[offset - 1], line[offset]].joined(separator: ",")
                } else {
                    return element
                }
            } }
            .map { $0.map { $0.trimmingCharacters(in: CharacterSet(charactersIn: "\"")) } }
        
print(parsedCSV)

То есть если предыдущий элемент начинался с кавычки и текущий заканичавается кавычкой, значит что-то тут не так) - и мы соединяем предыдущий с текущим. Только как теперь удалить предыдущий элемент?

[[“abc”, “def”, “ghi”, “123.4”, “567”, “qwe”, “qwe,rty”, “jkl”]]


#6

Можете просто создать новую переменную, которая будет записывать конечные данные в себя.
Только вам еще нужно реализовать условие для такой последовательности:
\"qwe,rty,uio\"
когда в массиве будет элемент без кавычек, который находится между элементами с открывающей и закрыващей кавычками. Т.е. таких элементов может быть несколько.


#7

Кажется, получилось

    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 = last + 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”]