369

I have the following simple code written in Swift 3:

let str = "Hello, playground"
let index = str.index(of: ",")!
let newStr = str.substring(to: index)

From Xcode 9 beta 5, I get the following warning:

'substring(to:)' is deprecated: Please use String slicing subscript with a 'partial range from' operator.

How can this slicing subscript with partial range from be used in Swift 4?

1
  • 1
    var str = "Hello, playground" let indexcut = str.firstIndex(of: ",") print(String(str[..<indexcut!])) print(String(str[indexcut!...])) Commented Jul 24, 2019 at 12:05

21 Answers 21

436

You should leave one side empty, hence the name "partial range".

let newStr = str[..<index]

The same stands for partial range from operators, just leave the other side empty:

let newStr = str[index...]

Keep in mind that these range operators return a Substring. If you want to convert it to a string, use String's initialization function:

let newStr = String(str[..<index])

You can read more about the new substrings here.

Sign up to request clarification or add additional context in comments.

9 Comments

str[..<index] returns a Substring. If you want newStr to be a Stringyou have to write: let newStr = "\(str[..<index])"
Using string interpolation with a lone Substring is probably slightly confusing, since what you are really trying to accomplish is String initialization: let newStr = String(str[..<index]).
Updating code where my 'index' value was simply an integer yields an error message, Cannot subscript a value of type 'String' with an index of type 'PartialRangeUpTo<Int>' . What types of values have to be used there?
@ConfusionTowers, Swift string indices are not integers, and that hasn't changed with version 4. You'll probably need str[..<str.index(str.startIndex, offsetBy: 8)] or something like that. Keep in mind that str.index is a linear-time operation in function of offsetBy.
@zneak You probably want str.prefix(8)
|
300

Convert Substring (Swift 3) to String Slicing (Swift 4)

Examples In Swift 3, 4:

let newStr = str.substring(to: index) // Swift 3
let newStr = String(str[..<index]) // Swift 4

let newStr = str.substring(from: index) // Swift 3
let newStr = String(str[index...]) // Swift 4 

let range = firstIndex..<secondIndex // If you have a range
let newStr = = str.substring(with: range) // Swift 3
let newStr = String(str[range])  // Swift 4

2 Comments

Perfecto, and thanks for giving the 3 and 4 examples side by side, makes updating my project way easier!
This seems so needlessly complicated.
134

Swift 5, 4

Usage

let text = "Hello world"
text[0] // H
text[...3] // "Hell"
text[6..<text.count] // world
text[NSRange(location: 6, length: 3)] // wor

Code

import Foundation

public extension String {
  subscript(value: Int) -> Character {
    self[index(at: value)]
  }
}

public extension String {
  subscript(value: NSRange) -> Substring {
    self[value.lowerBound..<value.upperBound]
  }
}

public extension String {
  subscript(value: CountableClosedRange<Int>) -> Substring {
    self[index(at: value.lowerBound)...index(at: value.upperBound)]
  }

  subscript(value: CountableRange<Int>) -> Substring {
    self[index(at: value.lowerBound)..<index(at: value.upperBound)]
  }

  subscript(value: PartialRangeUpTo<Int>) -> Substring {
    self[..<index(at: value.upperBound)]
  }

  subscript(value: PartialRangeThrough<Int>) -> Substring {
    self[...index(at: value.upperBound)]
  }

  subscript(value: PartialRangeFrom<Int>) -> Substring {
    self[index(at: value.lowerBound)...]
  }
}

private extension String {
  func index(at offset: Int) -> String.Index {
    index(startIndex, offsetBy: offset)
  }
}

10 Comments

this functionality should be default swift behavior.
Definitely PR this into Swift lib :D
This is a fix of the ugliest part of the Swift.
This is a bad answer since the subscript operator hides the O(n) complexity of the index-function. A good programming API only use subscript to denote fast lookup.
@ragnarius - In that respect it is no worse than the core library
|
82

Shorter in Swift 4/5:

let string = "123456"
let firstThree = String(string.prefix(3)) //"123"
let lastThree = String(string.suffix(3)) //"456"

2 Comments

This only works if your string has integers, you can't do this for actual string suffix argument, thus does not answer the question.
let string = "hello world" - will not work for this. The argument for prefix and suffix in your case is Integer. Methods don't have argument for String such as string.prefix("world")
34

Swift5

(Java's substring method):

extension String {
    func subString(from: Int, to: Int) -> String {
       let startIndex = self.index(self.startIndex, offsetBy: from)
       let endIndex = self.index(self.startIndex, offsetBy: to)
       return String(self[startIndex..<endIndex])
    }
}

Usage:

var str = "Hello, Nick Michaels"
print(str.subString(from:7,to:20))
// print Nick Michaels

4 Comments

Still works in Swift 5. I was looking for a Java style substring (from to to-1, e.g. "Hello".substring(1,4) returns "ell"). With a small modification (startIndex..<endIndex) this is the best solution I've found so far that does exactly that with just a few lines of code.
This works well and is by far the easiest solution of all. Thanks!
I love this answer!
Just a quick note on the usage: the index is 0 based, as with most indexes. If you wanted to return the first five characters of the string you would use: print(str.subString(from:0,to:5)) So from your string - "Hello, Nick Michaels" The output would be: "Hello" If you wanted to get "Nick" from the above string you would use: print(str.subString(from:7,to:10))
29

The conversion of your code to Swift 4 can also be done this way:

let str = "Hello, playground"
let index = str.index(of: ",")!
let substr = str.prefix(upTo: index)

You can use the code below to have a new string:

let newString = String(str.prefix(upTo: index))

Comments

21

substring(from: index) Converted to [index...]

Check the sample

let text = "1234567890"
let index = text.index(text.startIndex, offsetBy: 3)

text.substring(from: index) // "4567890"   [Swift 3]
String(text[index...])      // "4567890"   [Swift 4]

2 Comments

characters are deprecated in Swift 4, I think you have to change the example to get the index for Swift 4
This helped me. tnx
13

Some useful extensions:

extension String {
    func substring(from: Int, to: Int) -> String {
        let start = index(startIndex, offsetBy: from)
        let end = index(start, offsetBy: to - from)
        return String(self[start ..< end])
    }

    func substring(range: NSRange) -> String {
        return substring(from: range.lowerBound, to: range.upperBound)
    }
}

1 Comment

Interesting, I was thinking the same. Is String(line["http://".endIndex...]) clearer than the deprecated substring? line.substring(from: "http://".endIndex) maybe until they get the stated goal of amazing string handling, they should not deprecate substring.
7

Example of uppercasedFirstCharacter convenience property in Swift3 and Swift4.

Property uppercasedFirstCharacterNew demonstrates how to use String slicing subscript in Swift4.

extension String {

   public var uppercasedFirstCharacterOld: String {
      if characters.count > 0 {
         let splitIndex = index(after: startIndex)
         let firstCharacter = substring(to: splitIndex).uppercased()
         let sentence = substring(from: splitIndex)
         return firstCharacter + sentence
      } else {
         return self
      }
   }

   public var uppercasedFirstCharacterNew: String {
      if characters.count > 0 {
         let splitIndex = index(after: startIndex)
         let firstCharacter = self[..<splitIndex].uppercased()
         let sentence = self[splitIndex...]
         return firstCharacter + sentence
      } else {
         return self
      }
   }
}

let lorem = "lorem".uppercasedFirstCharacterOld
print(lorem) // Prints "Lorem"

let ipsum = "ipsum".uppercasedFirstCharacterNew
print(ipsum) // Prints "Ipsum"

1 Comment

If you mean substring(with: range) -> self[range]
7

You can create your custom subString method using extension to class String as below:

extension String {
    func subString(startIndex: Int, endIndex: Int) -> String {
        let end = (endIndex - self.count) + 1
        let indexStartOfText = self.index(self.startIndex, offsetBy: startIndex)
        let indexEndOfText = self.index(self.endIndex, offsetBy: end)
        let substring = self[indexStartOfText..<indexEndOfText]
        return String(substring)
    }
}

1 Comment

If this is going to take in an endIndex, it needs to be able to handle out of bounds as well.
5

Creating SubString (prefix and suffix) from String using Swift 4:

let str : String = "ilike"
for i in 0...str.count {
    let index = str.index(str.startIndex, offsetBy: i) // String.Index
    let prefix = str[..<index] // String.SubSequence
    let suffix = str[index...] // String.SubSequence
    print("prefix \(prefix), suffix : \(suffix)")
}

Output

prefix , suffix : ilike
prefix i, suffix : like
prefix il, suffix : ike
prefix ili, suffix : ke
prefix ilik, suffix : e
prefix ilike, suffix : 

If you want to generate a substring between 2 indices , use :

let substring1 = string[startIndex...endIndex] // including endIndex
let subString2 = string[startIndex..<endIndex] // excluding endIndex

2 Comments

let prefix = str[...<index>] instead of str[..<index>] single dot is missing.
@AbuTaareq, which one you are talking about? let prefix = str[..<index], it is perfect. (prefix string). Try in play ground to get more context.
4

I have written a string extension for replacement of 'String: subString:'

extension String {
    
    func sliceByCharacter(from: Character, to: Character) -> String? {
        let fromIndex = self.index(self.index(of: from)!, offsetBy: 1)
        let toIndex = self.index(self.index(of: to)!, offsetBy: -1)
        return String(self[fromIndex...toIndex])
    }
    
    func sliceByString(from:String, to:String) -> String? {
        //From - startIndex
        var range = self.range(of: from)
        let subString = String(self[range!.upperBound...])
        
        //To - endIndex
        range = subString.range(of: to)
        return String(subString[..<range!.lowerBound])
    }
    
}

Usage : "Date(1511508780012+0530)".sliceByString(from: "(", to: "+")

Example Result : "1511508780012"

PS: Optionals are forced to unwrap. Please add Type safety check wherever necessary.

1 Comment

Caution : optionals are forced to unwrap. please add Type safety check if necessary.
4

If you are trying to just get a substring up to a specific character, you don't need to find the index first, you can just use the prefix(while:) method

let str = "Hello, playground"
let subString = str.prefix { $0 != "," } // "Hello" as a String.SubSequence

1 Comment

Thanks! I learned a lot from this. If anyone else struggles to understand the syntax, it is well explained in docs.swift.org/swift-book/LanguageGuide/Closures.html Read about "Closure Expressions" and "Trailing Closures".
3

When programming I often have strings with just plain A-Za-z and 0-9. No need for difficult Index actions. This extension is based on the plain old left / mid / right functions.

extension String {

    // LEFT
    // Returns the specified number of chars from the left of the string
    // let str = "Hello"
    // print(str.left(3))         // Hel
    func left(_ to: Int) -> String {
        return "\(self[..<self.index(startIndex, offsetBy: to)])"
    }

    // RIGHT
    // Returns the specified number of chars from the right of the string
    // let str = "Hello"
    // print(str.left(3))         // llo
    func right(_ from: Int) -> String {
        return "\(self[self.index(startIndex, offsetBy: self.length-from)...])"
    }

    // MID
    // Returns the specified number of chars from the startpoint of the string
    // let str = "Hello"
    // print(str.left(2,amount: 2))         // ll
    func mid(_ from: Int, amount: Int) -> String {
        let x = "\(self[self.index(startIndex, offsetBy: from)...])"
        return x.left(amount)
    }
}

1 Comment

Great idea!! Sad though that there is a need to abstract Swift-features just because they're constantly changing how things work. Guess they want us all to focus on constructs instead of productivity. Anyway, I made some minor updates to your fine code: pastebin.com/ManWmNnW
2

Hope this will help little more :-

var string = "123456789"

If you want a substring after some particular index.

var indexStart  =  string.index(after: string.startIndex )// you can use any index in place of startIndex
var strIndexStart   = String (string[indexStart...])//23456789

If you want a substring after removing some string at the end.

var indexEnd  =  string.index(before: string.endIndex)
var strIndexEnd   = String (string[..<indexEnd])//12345678

you can also create indexes with the following code :-

var  indexWithOffset =  string.index(string.startIndex, offsetBy: 4)

Comments

2

with this method you can get specific range of string.you need to pass start index and after that total number of characters you want.

extension String{
    func substring(fromIndex : Int,count : Int) -> String{
        let startIndex = self.index(self.startIndex, offsetBy: fromIndex)
        let endIndex = self.index(self.startIndex, offsetBy: fromIndex + count)
        let range = startIndex..<endIndex
        return String(self[range])
    }
}

Comments

2

This is my solution, no warning, no errors, but perfect

let redStr: String = String(trimmStr[String.Index.init(encodedOffset: 0)..<String.Index.init(encodedOffset: 2)])
let greenStr: String = String(trimmStr[String.Index.init(encodedOffset: 3)..<String.Index.init(encodedOffset: 4)])
let blueStr: String = String(trimmStr[String.Index.init(encodedOffset: 5)..<String.Index.init(encodedOffset: 6)])

1 Comment

The use of encodedOffset is considered harmful and will be deprecated.
2

the simples way that I use is :

String(Array(str)[2...4])

Comments

1
var str = "Hello, playground"
let indexcut = str.firstIndex(of: ",")
print(String(str[..<indexcut!]))
print(String(str[indexcut!...]))

You can try in this way and will get proper results.

Comments

0

Swift 4, 5, 5+

Substring from Last

let str = "Hello World"
let removeFirstSix = String(str.dropFirst(6))
print(removeFirstSix) //World

Substring from First

let removeLastSix = String(str.dropLast(6))
print(removeLastSix) //Hello

Comments

-1

Hope it would be helpful.

extension String {
    func getSubString(_ char: Character) -> String {
        var subString = ""
        for eachChar in self {
            if eachChar == char {
                return subString
            } else {
                subString += String(eachChar)
            }
        }
        return subString
    }
}


let str: String = "Hello, playground"
print(str.getSubString(","))

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.