'How to return a first word from a string in Swift?

If we have, for example, situation like this:

 var myString = "Today was a good day"

What is the best way to return the first word, which is "Today"? I think mapping should be applied, but not sure how.

Thanks.



Solution 1:[1]

The simplest way I can think of is

Swift 3

let string = "hello world"
let firstWord = string.components(separatedBy: " ").first

Swift 2.2

let string = "hello world"
let firstWord = string.componentsSeparatedByString(" ").first

and if you think you need to use it a lot in your code, make it as an extension

extension String {
    func firstWord() -> String? {
        return self.components(separatedBy: " ").first
    }
}

Usage

let string = "hello world"
let firstWord = string.firstWord()

Solution 2:[2]

You can use StringProtocol method enumerateSubstrings(in: Range<String.Index>) with options .byWords to enumerate the words in your string and just get the first element:

Swift 5.1 • Xcode 11 or later

Note: For older Swift syntax check this post edit history

import Foundation

extension StringProtocol {

    var byLines: [SubSequence] { components(separated: .byLines) }
    var byWords: [SubSequence] { components(separated: .byWords) }

    func components(separated options: String.EnumerationOptions)-> [SubSequence] {
        var components: [SubSequence] = []
        enumerateSubstrings(in: startIndex..., options: options) { _, range, _, _ in components.append(self[range]) }
        return components
    }

    var firstWord: SubSequence? {
        var word: SubSequence?
        enumerateSubstrings(in: startIndex..., options: .byWords) { _, range, _, stop in
            word = self[range]
            stop = true
        }
        return word
    }
    var firstLine: SubSequence? {
        var line: SubSequence?
        enumerateSubstrings(in: startIndex..., options: .byLines) { _, range, _, stop in
            line = self[range]
            stop = true
        }
        return line
    }
}

Playground Testing:

let string = "• Today was a good day.\n• Tomorrow will be better.\n"

let firstWord = string.firstWord                               // "Today"
let firstLine = string.firstLine                               // "• Today was a good day."
let firstLineLastWord = string.firstLine?.byWords.last         // day
let firstLineLast2Words = string.firstLine?.byWords.suffix(2)  // ["good", "day"]

Solution 3:[3]

I would prefer using CharacterSet, since words can be delimited by white-spaces as well as punctuation marks.

var myString    = "Today was a good day"
let nonLetters  = CharacterSet.letters.inverted
let first       = myString.components(separatedBy: nonLetters).first

Solution 4:[4]

To avoid processing the whole string just to get the first word, you could do this:

let string = "Hello World"
let word1  = string.prefix{ (c:Character) in CharacterSet.letters.contains(c.unicodeScalars.first!) }

Solution 5:[5]

Try using prefix() function

let string = "Today was a good day"
if let spaceIndex = string.firstIndex(of: " ") {
    let firstWord = String(string.prefix(upTo: string.index(after: spaceIndex)))
    print(firstWord)      // Today
}

Solution 6:[6]

Elegant solution:

extension String {

    var firstWord: String {
        self.components(separatedBy: " ").first ?? ""
    }
}

Usage:

let myString = "Today was a good day"
print(myString.firstWord)

output:

Today

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2
Solution 3 Vinod Vishwanath
Solution 4 Alain T.
Solution 5 Rachit Agarwal
Solution 6 Ali Hamad