fetzig
fetzig

Reputation: 1664

Split String into Array keeping delimiter/separator in Swift

Looking for an (elegant) solution for splitting a string and keeping the separator as item(s) in the array

example 1:

"hello world"

["hello", " ", "world"]

example 2:

" hello world"

[" ", "hello", " ", "world"]

thx.

Upvotes: 5

Views: 2281

Answers (4)

Roger Lee
Roger Lee

Reputation: 320

let sample = "a\nb\n\nc\n\n\nd\n\nddddd\n \n  \n  \n\n"

let sep = "\n"

let result = sample.components(separatedBy: sep).flatMap {
    $0 == "" ? [sep] : [$0, sep]
}.dropLast()


debugPrint(result) // ArraySlice(["a", "\n", "b", "\n", "\n", "c", "\n", "\n", "\n", "d", "\n", "\n", "ddddd", "\n", " ", "\n", "  ", "\n", "  ", "\n", "\n"])

Upvotes: 0

vadian
vadian

Reputation: 285069

Just for fun, the Swift Algorithms package contains an algorithm called Intersperse

After adding the package and

import Algorithms

you can write

let string = "hello world"
let separator = " "

let result = Array(string
                     .components(separatedBy: separator)
                     .interspersed(with: separator))
print(result)

Your second example is barely correct, the result of splitting " hello world" by space is

["", "hello", "world"]

Upvotes: 0

Logan
Logan

Reputation: 53112

For people who have a condition for their split, for example: splitting a camelCaseString based on uppercase condition:

extension Sequence {
    func splitIncludeDelimiter(whereSeparator shouldDelimit: (Element) throws -> Bool) rethrows -> [[Element]] {
        try self.reduce([[]]) { group, next in
            var group = group
            if try shouldDelimit(next) {
                group.append([next])
            } else {
                group[group.lastIdx].append(next)
            }
            return group
        }
    }
}

For example:

"iAmCamelCase".splitIncludeDelimiter(whereSeparator: \.isUppercase)
=>
["i", "Am", "Camel", "Case"]

(If you want the imp of isUppercase)

extension CharacterSet {
    static let uppercaseLetters = CharacterSet(charactersIn: "ABCDEFGHIJKLMNOPQRSTUVWXYZ")
}

extension Unicode.Scalar {
    var isUppercase: Bool {
        CharacterSet.uppercaseLetters.contains(self)
    }
}

Upvotes: 1

Sweeper
Sweeper

Reputation: 271030

Suppose you are splitting the string by a separator called separator, you can do the following:

let result = yourString.components(separatedBy:  separator) // first split
                        .flatMap { [$0, separator] } // add the separator after each split
                        .dropLast() // remove the last separator added
                        .filter { $0 != "" } // remove empty strings

For example:

let result = " Hello World ".components(separatedBy:  " ").flatMap { [$0, " "] }.dropLast().filter { $0 != "" }
print(result) // [" ", "Hello", " ", "World", " "]

Upvotes: 11

Related Questions