362

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?

Leo Dabus
  • 229,809
  • 59
  • 489
  • 571
Adrian
  • 19,440
  • 34
  • 112
  • 219

21 Answers21

434

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.

Dmitry
  • 14,306
  • 23
  • 105
  • 189
Tamás Sengel
  • 55,884
  • 29
  • 169
  • 223
  • 8
  • 13
    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[.. – Gary Aug 31 '17 at 19:06
  • 8
    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'` . What types of values have to be used there? – ConfusionTowers Sep 22 '17 at 20:50
  • 28
    @ConfusionTowers, [Swift string indices are not integers](https://stackoverflow.com/a/24905366/251153), and that hasn't changed with version 4. You'll probably need `str[.. – zneak Sep 22 '17 at 21:09
  • 8
    @zneak You probably want `str.prefix(8)` – Tim Vermeulen Sep 24 '17 at 17:31
  • 6
    Ugly syntax. Hate Swift for such expressions: ?? !! a!!a ?a a? [.. – Roman M Dec 15 '17 at 23:33
  • Is there an operator for substring from index to end but without the sign at the index? `str[index>..]` does not work :( Or do I need to offset the index? – ndreisg Oct 03 '18 at 14:24
  • how to create a index from a int ? – Ammar Mujeeb Dec 24 '18 at 06:31
  • 3
    Why Swift got to make things so complicated? Python's string manipulation are so much better `str = "Hello Python" print(str[0:2])` result is "He" – NamNamNam May 14 '19 at 04:12
296

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
Mohammad Sadegh Panadgoo
  • 3,929
  • 1
  • 10
  • 12
131

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)
  }
}
Community
  • 1
  • 1
dimpiax
  • 12,093
  • 5
  • 62
  • 45
81

Shorter in Swift 4/5:

let string = "123456"
let firstThree = String(string.prefix(3)) //"123"
let lastThree = String(string.suffix(3)) //"456"
ilnur
  • 865
  • 6
  • 7
  • This only works if your string has integers, you can't do this for actual string suffix argument, thus does not answer the question. – Mishka Apr 13 '22 at 20:08
  • Can you add more info about your case? I don't really understand what do you mean by saying "string has integers" and "actual suffix argument"? You can get index of whatever you want in your string and cut out what you need by using that index. – ilnur Apr 14 '22 at 07:13
  • 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") – Mishka Apr 14 '22 at 13:35
  • It's not "my case". It's how those methods work. `let string = "Hello world" let firstThree = String(string.prefix(3)) //"Hel" let lastThree = String(string.suffix(3)) //"rld"` Just find index that you need using another answers Maybe that helps: [link](https://stackoverflow.com/questions/40328242/how-to-get-range-of-substring-in-swift3) – ilnur Apr 14 '22 at 20:01
32

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
August Lin
  • 1,249
  • 12
  • 11
  • 2
    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.. – Neph Jun 13 '19 at 14:04
  • This works well and is by far the easiest solution of all. Thanks! – vfxdev Sep 02 '20 at 12:05
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))
Tamás Sengel
  • 55,884
  • 29
  • 169
  • 223
Thyerri Mezzari
  • 388
  • 2
  • 6
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]
Den
  • 3,179
  • 29
  • 26
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)
    }
}
  • 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. – possen Oct 22 '17 at 05:55
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"
Vlad
  • 6,402
  • 1
  • 60
  • 74
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)
    }
}
Chhaileng
  • 2,428
  • 1
  • 27
  • 24
  • If this is going to take in an endIndex, it needs to be able to handle out of bounds as well. – Jay May 03 '20 at 00:43
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
Stephen Rauch
  • 47,830
  • 31
  • 106
  • 135
Ashis Laha
  • 2,176
  • 3
  • 16
  • 17
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.

Community
  • 1
  • 1
byJeevan
  • 3,728
  • 3
  • 37
  • 60
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
Abizern
  • 146,289
  • 39
  • 203
  • 257
  • Thanks! I learned a lot from this. If anyone else struggles to understand the syntax, it is well explained in https://docs.swift.org/swift-book/LanguageGuide/Closures.html Read about "Closure Expressions" and "Trailing Closures". – Magnus Jul 27 '21 at 07:43
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)
    }
}
Vincent
  • 4,342
  • 1
  • 38
  • 37
  • 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: https://pastebin.com/ManWmNnW – Fredrik Johansson Nov 22 '17 at 11:17
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)])
itsji10dra
  • 4,603
  • 3
  • 39
  • 59
Johnny
  • 1,112
  • 1
  • 13
  • 21
  • 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
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)
Anurag Bhakuni
  • 2,379
  • 26
  • 32
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])
    }
}
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.

OhhhThatVarun
  • 3,981
  • 2
  • 26
  • 49
user1828845
  • 1,304
  • 1
  • 10
  • 17
1

the simples way that I use is :

String(Array(str)[2...4])
Hamish
  • 1,685
  • 22
  • 37
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
Sandeep Maurya
  • 1,979
  • 17
  • 22
-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(","))
Anand Verma
  • 572
  • 1
  • 6
  • 11