1

I understand that I can fallback to the NSString function componentsSeparatedByString, and so perhaps this is a nitpick, but one of the things I like about Swift is that it is designed around brevity and short syntax.

I was really hoping I could just: var parts = myString.characters.split("${") but that function only works for a single Character, not a two Character string. I even tried var parts = myString.characters.split { $0 == "${" } but that is expecting a single Character as the delimiter and not a full String. :(

Is there an api function that I'm missing or do I need to stick with the the old NSString bridged functions?

vikingosegundo
  • 52,040
  • 14
  • 137
  • 178
Kenny Wyland
  • 20,844
  • 26
  • 117
  • 229

3 Answers3

5

Here's a rather simple-minded approach that makes it possible to use Swift split on a single character:

extension String {
    mutating func replace(target:String, with:String) {
        while let r = self.rangeOfString(target) {
            self.replaceRange(r, with: with)
        }
    }
    func split(separator:String) -> Array<String> {
        var s = self
        s.replace(separator, with:"☞") // arbitrary improbable character :)
        return s.characters.split("☞").map{String($0)}
    }
}

var s = "the${cat${sat${on${the${mat"
let arr = s.split("${")

However, rangeOfString is actually a Foundation method on NSString; if you don't import Foundation (or UIKit), that code won't compile. So in reality it's no improvement over just calling componentsSeparatedByString. I don't actually understand your objection to it in the first place; Swift has holes exactly because it expects Foundation to be backing it up and filling those holes.

matt
  • 515,959
  • 87
  • 875
  • 1,141
  • Wrap this in an extension and the op still gets his terse syntax. – Dan Beaulieu Feb 25 '16 at 23:44
  • @DanBeaulieu You caught me with my pants down, I was in the middle of doing that. :) – matt Feb 25 '16 at 23:49
  • Yeah, I figured that I would have to go with an extension. – Kenny Wyland Feb 26 '16 at 03:58
  • As for the objection, I'm just being nitpicky. I never liked silly long names like `componentsSeparatedbyString` instead of just `split` in ObjC and I was just looking forward to a nice, simple function call in Swift but ended up finding wildly complicated code that has changed radically over the last year. :) – Kenny Wyland Feb 26 '16 at 04:01
  • Well, if that's the only issue, just define `split` in the extension to call `componentsSeparatedByString` and never mind my answer. :) After all, this ability to inject your own methods thru extensions is really cool. I've got _lots_ of labor-saving extensions on built-in Swift classes. It's just a pity that Swift gives you no way just to define a permanent external library of all your modifications. – matt Feb 26 '16 at 04:22
  • by the murphy's law my string contains "arbitrary improbable character" with high probability :-). please see my solution (answer), where import Foundation is not required – user3441734 Feb 26 '16 at 11:08
  • Swift 4 and 5 now have the `replacingOccurrences` method so you do not need to create the `replace` method yourself. Simply `self.replacingOccurrences(of: separator, with:"☞")`. See https://stackoverflow.com/a/24201206/9035706 – Eerik Sven Puudist Aug 20 '21 at 13:19
  • 1
    @EerikSvenPuudist Very good point. It's a very old answer! Swift years are like dog years. :) – matt Aug 20 '21 at 13:24
0

'pure' Swift's solution where import Foundation is NOT required and arbitrary improbable character doesn't exists

let str = "t{he${cat${sat${on${the${mat"
let splitBy = "${"

extension String {
    func split(splitBy: String)->[String] {
        if self.isEmpty { return [] }
        var arr:[String] = []
        var tmp = self
        var tmp1 = ""
        var i = self.startIndex
        let e = self.endIndex
        let c = splitBy.characters.count

        while i < e {
            let tag = tmp.hasPrefix(splitBy)
            if !tag {
                tmp1.append(tmp.removeAtIndex(tmp.startIndex))
                i = i.successor()
            } else {
                tmp.removeRange(Range(start: tmp.startIndex, end: tmp.startIndex.advancedBy(c)))
                i = i.advancedBy(c)
                arr.append(tmp1)
                tmp1 = ""
            }
        }

        arr.append(tmp1)
        return arr.filter{ !$0.isEmpty }
    }
}

let arr = str.split(splitBy) // ["t{he", "cat", "sat", "on", "the", "mat"]
user3441734
  • 16,722
  • 2
  • 40
  • 59
0

If you have Foundation imported, you can use the components(separatedBy:) method to accomplish that.

let str = "Foo, Bar, Baz"
str.components(separatedBy: ", ")

Here are the docs.

(Tested on Ubuntu Linux)

Eerik Sven Puudist
  • 2,098
  • 2
  • 23
  • 42
  • You can see in the document you linked that `components(separatedBy:)` in Swift is a bridge to `componentsSeparatedByString` in the Foundation framework, which is already mentioned in the question and thus is not the answer to the question :). This is unrelated to Swift 5 (it's been there since iOS 2, actually). – Eric Aya Aug 20 '21 at 13:46