Swift version of componentsSeparatedByString
Asked Answered
B

4

27

I know its noob question, i really search around before ask. But there is not exact answer of what i want to know. How we split string into the array without using Objective C? For example:

var str = "Today is so hot"
var arr = str.componentsSeparatedByString(" ")  // *
  • I know it doesnt work but i am looking for like that. I want to split string with " " (or another char/string)

Idea:It might be very good for me, making extension of string class. But i dont know how i do that.

Edit: Forgetting import Foundation. If I import foundation it will work. But is there any way to do with extending String class? Thank you

Breastfeed answered 10/8, 2014 at 8:40 Comment(3)
There is the distinct possibility that both String and NSString have/share the same underlaying code, possibly CFString. In such case for componentsSeparatedByString there is really no difference.Hinds
the edit in the question doesn't really make sense unfortunately. Consider rewording, changing your question title, or ask a different - related - question?Hent
Since MartinR is just linking to Stuart's answer now, consider changing the accepted answer.Confident
O
33

If you want to split a string by a given character then you can use the built-in split() method, without needing Foundation:

let str = "Today is so hot"
let arr = split(str, { $0 == " "}, maxSplit: Int.max, allowEmptySlices: false)
println(arr) // [Today, is, so, hot]

Update for Swift 1.2: The order of the parameters changed with Swift 1.2 (Xcode 6.3), compare split now complains about missing "isSeparator":

let str = "Today is so hot"
let arr = split(str, maxSplit: Int.max, allowEmptySlices: false, isSeparator: { $0 == " "} )
println(arr) // [Today, is, so, hot]

Update for Swift 2: See Stuart's answer.

Update for Swift 3:

let str = "Today is so hot"
let arr = str.characters.split(separator: " ").map(String.init)
print(arr)
Orbit answered 10/8, 2014 at 15:7 Comment(1)
As mention by @The Paramagnetic Croiss, this work out of the box in Foundation. You need more kiss... (keep it simple stupid). componentsSeparatedByString does exactly what it says just put the right character, event space work!Olibanum
R
18

In Swift 2, the syntax for this has got more concise. The top-level split function is now a method on CollectionType (which String.CharacterView conforms to).

There are two versions of the method, the first takes a closure as a predicate to indicate whether a given element should be treated as a separator, and the other simply takes an element to specify as the separator - this is likely what you want for 99% of string splits. They both have a couple of defaulted parameters (see the docs for details) which helps keep the method call nice and clear.

It's worth noting that split(_:) returns a SubSequence (basically a Slice), so in most cases needs transforming back into an array of Strings which is generally more useful.

let str = "Today is so hot"
let words = str.characters.split(" ").map { String($0) }  // or `.map(String.init)`

 Explaining the shorthand initializer expression (map(String.init))

map is a method that accepts a function as an argument. Most of the time, you probably just use a trailing closure (an unnamed function) as the argument to map, e.g.:

func createString(from character: Character) -> String {
    // ...
}

let strings = characters.map { createString(from: $0) }

But the following is more concise, and just as valid:

let strings = characters.map(createString(from:))
// or even:
let strings = characters.map(createString) // argument names inferred from context.

In the above example, createString(from:) and createString are both function expressions. map expects a function as an argument, and a function expression can be passed as that argument. You can pass a function expression anywhere that accepts a function as an argument, which is why you can use sort like this for a types that conform to Comparable:

let sortedStrings = strings.sorted(by: <)

// `<` is just a function expression for a function that is essentially declared something like this:
func <(lhs: String, rhs: String) -> Bool {
    // ...
}

String.init is an initializer expression. It can be used in just the same way as a function expression – it is itself describing a function that takes a single Character as an argument, and returns a value of type String (though String.init is overloaded and can be passed many different types of argument).

To help clarify what is going on, consider the following code, where each invocation of map does exactly the same thing, but using an increasingly concise syntax:

// - Closure expression syntax used.
// - Explicit argument names & types.
// - Long-hand string initialization.
let strings = characters.map({ (character: CharacterView) -> String in
    return String.init(character)
})

// - Trailing closure syntax used (parentheses omitted).
// - Closure argument and return types inferred from context (type names omitted).
// - Short-hand (standard, really) string initialization.
let strings = characters.map { character in
    return String(character)
}

// - Implicit return since using single expression in the closure (`return` keyword omitted).
let strings = characters.map { character in String(character) }

// - Shorthand argument names (`in` keyword and argument names omitted).
let strings = characters.map { String($0) }

// - Initializer expression syntax used (curly braces omitted, argument implicitly passed to the initializer).
let strings = characters.map(String.init(_:))

// - Initializer expression argument names inferred from context. 
let strings = characters.map(String.init)
Residuum answered 9/8, 2015 at 17:15 Comment(7)
Or str.characters.split(" ").map(String.init).Orbit
@MartinR or Stuart, is there any reason to prefer one over the other? map(String.init) looks a little cleaner to me.Confident
@Confident No real difference, just reformatted. I also marginally prefer map(String.init) in the interest of eliminating the unnamed closure parameter, but I’d say it comes down to personal taste.Residuum
@Confident Hello, could you tell me what shortcut principle of map(String.init) is? Don't know what keyword to search for detailed doc.Collision
@Confident I've added a section that talks about that particular piece of syntax. For documentation, take a look through the sections of The Swift Programming Language on functions and closures, or look up function/closure/initializer expression syntax in the language reference.Residuum
@Confident and Stuart Thanks bro. Swift's implicit expression really makes beginner like me confused sometimes.Collision
Nice. This is one of the better and more concise explanations I've seen. I'd upvote you again if I could.Confident
P
9

In Swift 3.0 Use components(separatedBy:) on String than componentsSeparatedByString.

Sharing code sample

let tempString = "1.Wash your hands\n2.Check you phone\n3.Click home button".components(separatedBy: "\n")
print(tempString)
Porphyroid answered 17/10, 2016 at 22:6 Comment(0)
E
1

"I know it doesnt work"

Well, for me, it does. In the Swift REPL:

  1> import Foundation
  2> "a b c".componentsSeparatedByString(" ")
$R6: String[] = size=3 {
  [0] = {
    core = {
      _baseAddress = Builtin.RawPointer = 0x0000000100407980
      _countAndFlags = -4611686018427387903
      _owner = Some {
        Some = @"a"
      }
    }
  }
  [1] = {
    core = {
      _baseAddress = Builtin.RawPointer = 0x0000000100408e50 -> 0x00007fff7cde0062 (void *)0x001b00007fff7cdd
      _countAndFlags = -4611686018427387903
      _owner = Some {
        Some = @"b"
      }
    }
  }
  [2] = {
    core = {
      _baseAddress = Builtin.RawPointer = 0x0000000100408dd0
      _countAndFlags = -4611686018427387903
      _owner = Some {
        Some = @"c"
      }
    }
  }
}
Equalize answered 10/8, 2014 at 8:42 Comment(3)
Ah forget import foundation. Got it. But is there any way to do with extending string Class?Breastfeed
@Breastfeed What do you mean by "do with extending String class"? You don't have to do that. Conversion between String and NSString is implicit. It works like magic.Equalize
#25107103 I am looking for this kind of solution.Breastfeed

© 2022 - 2024 — McMap. All rights reserved.