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.
The simplest way I can think of is
let string = "hello world" let firstWord = string.components(separatedBy: " ").first 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 } } let string = "hello world" let firstWord = string.firstWord() let separators = " ,.;:*?" /* word boundaries */ let components = self.components(separatedBy: CharacterSet.init(charactersIn: separators) ) let firstWord = components.first?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"] 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!) } 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"