What is the way of extracting last word in a String in Swift? So if I have "Lorem ipsum dolor sit amet", return "amet". What is the most efficient way of doing this?
7 Answers
You can use String method enumerateSubstringsInRange. First parameter just pass your string Range<Index>, and the option .byWords. Just append each substring to the resulting collection and return it.
Swift 5 or later (for older Swift syntax check edit history)
import Foundation extension StringProtocol { // for Swift 4 you need to add the constrain `where Index == String.Index` var byWords: [SubSequence] { var byWords: [SubSequence] = [] enumerateSubstrings(in: startIndex..., options: .byWords) { _, range, _, _ in byWords.append(self[range]) } return byWords } } Usage:
let sentence = "Out of this world!!!" let words = sentence.byWords // ["Out", "of", "this", "world"] let firstWord = words.first // "Out" let lastWord = words.last // world" let first2Words = words.prefix(2) // ["Out", "of"] let last2Words = words.suffix(2) // ["this", "world"] Without import Foundation
Cleaning punctuation characters filtering the letters and spaces of the string
let clean = sentence.filter{ $0.isLetter || $0.isWhitespace } find the index after the index of the last space in a string
if let lastIndex = clean.lastIndex(of: " "), let index = clean.index(lastIndex, offsetBy: 1, limitedBy: clean.index(before: clean.endIndex)) { let lastWord = clean[index...] print(lastWord) // "world" } find the index of the first space in a string
if let index = clean.firstIndex(of: " ") { let firstWord = clean[...index] print(firstWord) // "Out"" } 3 Comments
O(n) performance. I'd be more inclined to make it a function, since that makes it clear that it's doing work every time you call it.components(separated: .byWords)"#". Btw it does return the last word "world" without the hashtagThe other answers are fine if you want to include Foundation classes. If you want to use Swift-only classes then you can do it this way:
One way to do it is to use indices. This is probably the fastest way with long strings:
Swift 4:
let str = "Lorem ipsum dolor sit amet" let size = str.reversed().firstIndex(of: " ") ?? str.count let startWord = str.index(str.endIndex, offsetBy: -size) let last = str[startWord...] // -> "amet" Or you could split the string:
Swift 4:
let str = "Lorem ipsum dolor sit amet" let split = str.split(separator: " ") let last = String(split.suffix(1).joined(separator: [" "])) let lastTwo = String(split.suffix(2).joined(separator: [" "])) print(last) // -> "amet" print(lastTwo) // -> "sit amet” Swift 3:
let str = "Lorem ipsum dolor sit amet" let split = str.characters.split(separator: " ") let last = String(split.suffix(1).joined(separator: [" "])) let lastTwo = String(split.suffix(2).joined(separator: [" "])) print(last) // -> "amet" print(lastTwo) // -> "sit amet” Swift 2:
let str = "Lorem ipsum dolor sit amet" let split = str.characters.split(Character(" ")) let last = String(split.suffix(1).joinWithSeparator([" "])) let lastTwo = String(split.suffix(2).joinWithSeparator([" "])) print(last) // -> "amet" print(lastTwo) // -> "sit amet" 2 Comments
I would also consider using componentsSeparatedByCharactersInSet, and using the whitespace character set:
let string = "Lorem ipsum dolor sit amet" let stringArray = string.componentsSeparatedByCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet()) print(stringArray.last) 3 Comments
String doesn't have the method componentsSeparatedByCharactersInSet. That method is part of NSString.First use componentsSeparatedByString to split your string into an array by space, then get the last word of the array using .last
var string = "Lorem ipsum dolor sit amet" var stringArr = string.componentsSeparatedByString(" ") var lastWord = stringArr.last //amet 1 Comment
Swift 5
extension String { func trim(_ emptyToNil: Bool = true)->String? { let text = self.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines) return emptyToNil && text.isEmpty ? nil : text } var lastWord: String? { if let size = self.lastIndex(of: " "), size >= self.startIndex { return String(self[size...]).trim() } return nil } } Usage
print("Out of this world!!!".lastWord ?? "") // world!!! Comments
The same solution by '@Leo Dabus' but without slices: (Swift 4.x)
let fullName = "Williams Diaz Robert" let words = fullName.components(separatedBy: " ") if(words.count < 2) { return } let fistName = String(words.last ?? "") //Robert let lastNameArray = words.prefix(words.count - 1) //["Williams","Diaz"]: [String] let lastName = lastNameArray.joined(separator: " ") // "Williams Diaz"