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.
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.
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", " "]
components(separatedBy:) that had an optional parameter to exclude empty results. Have you seen anything like that?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)
}
}
endIndex which can be used instead of lastIdxJust 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"]
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"])