20

This is using the example code from the official Swift4 doc

let greeting = "Hi there! It's nice to meet you! "
let endOfSentence = greeting.index(of: "!")!
let firstSentence = greeting[...endOfSentence]
// firstSentence == "Hi there!"

But lets say let greeting = "Hello there world!" and I want to retrieve only the second word (substring) in this sentence? So I only want the word "there".

I've tried using "world!" as an argument like let endOfSentence = greeting.index(of: "world!")! but Swift 4 Playground doesn't like that. It's expecting 'Character' and my argument is a string.

So how can I get a substring of a very precise subrange? Or get nth word in a sentence for greater use in the future?

Kent Wong
  • 566
  • 1
  • 6
  • 20

6 Answers6

19

You can search for substrings using range(of:).

import Foundation

let greeting = "Hello there world!"

if let endIndex = greeting.range(of: "world!")?.lowerBound {
    print(greeting[..<endIndex])
}

outputs:

Hello there 

EDIT:

If you want to separate out the words, there's a quick-and-dirty way and a good way. The quick-and-dirty way:

import Foundation

let greeting = "Hello there world!"

let words = greeting.split(separator: " ")

print(words[1])

And here's the thorough way, which will enumerate all the words in the string no matter how they're separated:

import Foundation

let greeting = "Hello there world!"

var words: [String] = []

greeting.enumerateSubstrings(in: greeting.startIndex..<greeting.endIndex, options: .byWords) { substring, _, _, _ in
    if let substring = substring {
        words.append(substring)
    }
}

print(words[1])

EDIT 2: And if you're just trying to get the 7th through the 11th character, you can do this:

import Foundation

let greeting = "Hello there world!"

let startIndex = greeting.index(greeting.startIndex, offsetBy: 6)
let endIndex = greeting.index(startIndex, offsetBy: 5)

print(greeting[startIndex..<endIndex])
Charles Srstka
  • 16,665
  • 3
  • 34
  • 60
  • Ah sorry, I should have been more clear. I want precisely the word "There". From a Java background, I would just shove the string into a string array and print from the indices 7 to 11. Is there no built in way in Swift4 using the substring members? – Kent Wong Sep 26 '17 at 05:09
  • @KentW Try that on for size. – Charles Srstka Sep 26 '17 at 05:22
  • Thanks! I didn't want to import foundation. Thorough answer. I couldn't find this in the Swift 4 iBook. – Kent Wong Sep 26 '17 at 05:42
  • I just want to know what make swift to get substring so complicated compared with other languages. – LF00 Jan 17 '18 at 06:21
18

For swift4,

let string = "substring test"
let start = String.Index(encodedOffset: 0)
let end = String.Index(encodedOffset: 10)
let substring = String(string[start..<end])
LF00
  • 27,015
  • 29
  • 156
  • 295
  • Note that if the string contains characters that require more than one UTF-16 code unit (like emojis), `String.Index(encodedOffset:)` may get you something different from what you expect. – Charles Srstka Nov 22 '18 at 14:02
  • 1
    The use of `encodedOffset` is [considered harmful](https://swift.org/blog/utf8-string/#use-of-stringindexencodedoffset-considered-harmful) and will be [deprecated](https://github.com/apple/swift-evolution/blob/master/proposals/0241-string-index-explicit-encoding-offset.md). – Martin R Mar 21 '19 at 08:03
8

In Swift 5 encodedOffset (swift 4 func) is deprecated.
You will need to use utf160Offset

// Swift 5     

let string = "Hi there! It's nice to meet you!"
let startIndex = 10 // random for this example
let endIndex = string.count

let start = String.Index(utf16Offset: startIndex, in: string)
let end = String.Index(utf16Offset: endIndex, in: string)

let substring = String(string[start..<end])

prints -> It's nice to meet you!

Suraj Rao
  • 29,388
  • 11
  • 94
  • 103
k-thorat
  • 4,873
  • 1
  • 27
  • 36
4

There is one mistake in the first answer.

Range<String.Index>.upperBound

The upperBound property should be the endIndex For Example:

let text = "From Here Hello World"
if let result = text.range(of: "Hello World") {
     let startIndex = result.upperBound
     let endIndex = result.lowerBound
     print(String(text[startIndex..<endIndex])) //"Hello World"
}
Wade
  • 41
  • 3
4

the simplest way I use is :

var str = "abcdefg"
String(Array(str)[2...4])
Hamish
  • 1,685
  • 22
  • 37
1

Old habits die hard. I did it the "Java" way and split the string up by spaces, then accessed the second word.

print(greeting.split(separator: " ")[1]) // "there /n"
Kent Wong
  • 566
  • 1
  • 6
  • 20