This method works on CollectionTypes, rather than Strings, but it should be easy enough to adapt:
extension CollectionType { func splitAt(@noescape isSplit: Generator.Element throws -> Bool) rethrows -> [SubSequence] { var p = startIndex return try indices .filter { i in try isSplit(self[i]) } .map { i in defer { p = i } return self[p..<i] } + [suffixFrom(p)] } } extension CollectionType where Generator.Element : Equatable { func splitAt(splitter: Generator.Element) -> [SubSequence] { return splitAt { el in el == splitter } } }
You could use it like this:
let sentence = "Hello, my name is oisdk. This should split: but only at punctuation!" let puncSet = Set("!.,:".characters) sentence .characters .splitAt(puncSet.contains) .map(String.init) // ["Hello", ", my name is oisdk", ". This should split", ": but only at punctuation", "!"]
Or, this version, which uses a for-loop, and splits after the delimiter:
extension CollectionType { func splitAt(@noescape isSplit: Generator.Element throws -> Bool) rethrows -> [SubSequence] { var p = startIndex var result: [SubSequence] = [] for i in indices where try isSplit(self[i]) { result.append(self[p...i]) p = i.successor() } if p != endIndex { result.append(suffixFrom(p)) } return result } } extension CollectionType where Generator.Element : Equatable { func splitAt(splitter: Generator.Element) -> [SubSequence] { return splitAt { el in el == splitter } } } let sentence = "Hello, my name is oisdk. This should split: but only at punctuation!" let puncSet = Set("!.,:".characters) sentence .characters .splitAt(puncSet.contains) .map(String.init) // ["Hello,", " my name is oisdk.", " This should split:", " but only at punctuation!"]
Or, if you wanted to get the most Swift features into one function (defer, throws, a Protocol extension, an evil flatMap, guard, and Optionals):
extension CollectionType { func splitAt(@noescape isSplit: Generator.Element throws -> Bool) rethrows -> [SubSequence] { var p = startIndex var result: [SubSequence] = try indices.flatMap { i in guard try isSplit(self[i]) else { return nil } defer { p = i.successor() } return self[p...i] } if p != endIndex { result.append(suffixFrom(p)) } return result } }
" '?!:;"That would make for funny strings, but not really what I need. => response to "what if you just concatenate the delimiter"