15

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?

0

7 Answers 7

30

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

3 Comments

Nice, although I'd be hesitant to have an extension that promotes a computed property with at least 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.
@DuncanC Thanks but I did already here stackoverflow.com/a/39667966/2303865 You can remove the computed properties and use the method only components(separated: .byWords)
@UtkuDalmaz There is no word that starts with "#". Btw it does return the last word "world" without the hashtag
16

The 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

nice solution but a word can be separated by a comma or punctuation mark too
The example in the question used spaces but the techniques work for any character. You could also use the methodfirstIndex(where:) like this: str.reversed().firstIndex { Set(" ,!.?;").contains($0) } and it could be combined with CharacterSet.punctuationCharacters too.
10

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

I like your approach! Thanks a lot! Is it possible to get the last two words with this approach or should I use a for loop?
Don't forget to add import Foundation to the answer. The example won't work without it.
Are you sure? You might have imported it somewhere. String doesn't have the method componentsSeparatedByCharactersInSet. That method is part of NSString.
9

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

For Swift 4, swift 5 and upper: .components(separatedBy: " ")
3

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

1

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" 

Comments

1
let value = "Hello, I am a String" let stringArray = value.components(separatedBy: .whitespaces) let lastWord = stringArray.last ?? "" print(lastWord) 

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.