13

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.

6 Answers 6

24

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() 
Sign up to request clarification or add additional context in comments.

1 Comment

Depending on the string, this might be too naive. E.g., "Hello, World!" would yield "Hello," which may or may not be what you wanted. Maybe try let separators = " ,.;:*?" /* word boundaries */ let components = self.components(separatedBy: CharacterSet.init(charactersIn: separators) ) let firstWord = components.first?
12

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"] 

Comments

7

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 

Comments

2

Elegant solution:

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

Usage:

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

output:

Today 

Comments

0

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!) } 

9 Comments

Note that If you don't want to enumerate the whole string you can stop the enumeratedSubsrtrings in range after finding the first word.
Why not simply prefix { $0 != " " }? If you are extra paranoid prefix { String($0).rangeOfCharacter(from: .whitespaces) == nil } or using the letters approach prefix { String($0).rangeOfCharacter(from: .letters) != nil } Note that all of this only work if the word is at the beginning of the string. try "•Sugar"
I wanted to make sure that any non-letter delimiter would be detected (not just spaces). Also, transforming each letter into a string for processing didn't seem as straightforward (or efficient) to me.
Using only the first Unicode value doesn't seem also correct
It would not work for composite unicode characters such as emojis but for all roman character sets it does work.
|
0

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 } 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.