How to Get Substring With NSRange in Swift 5

by


Warning:

substring(with:)’ is deprecated: Please use String slicing subscript.

In Swift 5 we do no longer have access to substring() methods for they are deprecated. We will discuss all alternatives and understand them in details.

  • How to access Characters in String?
  • Why Int based Subscript is not available in Swift?
  • What is difference between Range and NSRange?
  • How does String Indices work?
  • How to create Range from String Indices?
  • How to get substring with Range?
  • How to get substring with NSRange?

Swift Programming Language Guide:

In String, different characters can require different amounts of memory to store, so in order to determine which Character is at a particular position, you must iterate over each Unicode scalar from the start or end of that String. For this reason, Swift strings can’t be indexed by integer values.

let testString = "hello"
testString[2]

will give an error:
'subscript(_:)' is unavailable: cannot subscript String with an Int, see the documentation comment for discussion


We no longer access character or substring from String with Int based subscript and we will discuss the reason why soon. One way we can access the individual Character values for a String is by iterating over the string with a for-in loop

for character in "hello" {
    print(character)
}
Output:
// h
// e
// l
// l
// o


Another way to efficiently access range of characters in String is to use Range based subscript. Ranges in Swift allow us to select parts of Strings, collections, and other types. They’re the Swift variant of NSRange which we know from Objective-C. There is difference between workings of Range and NSRange. We will discuss the difference between them with example context of Strings.

NSRange

A structure used to describe a portion of a series, such as characters in a string or objects in an array.
Lets look at two members of NSRange:
locationlocation is the starting index in the range (zero based).
lengthlength is the number of entries in the range.

Why are we discussing NSRange in Swift when we have Range. There will be situations where we come across NSRange in Swift. For example NSTextCheckingResult returned from regular expression match gives NSRange.

Now: Lets see an code example on usage of NSRange in Objective-C


NSString *testString = @“Cat!🐱!!”;
NSRange range = NSMakeRange (3, 3);
NSLog (@“substring: %@”, [testString substringWithRange:range]);
// Expected: !🐱!
// Actually returns: !🐱


Note:

Earlier i mentioned from the Swift guide that different characters in strings can require different amounts of memory to store.
In above example NSRange is using absolute Int based subscript to get us substring. Cat emoji from example use more space than regular character so it returns only 2 characters instead of expected 3 characters. This phenomenon marks one of the important differences in the workings of Range and NSRange. This is also the reason why we no longer access character or substring from String with Int based subscript in Swift

We are still under the context of Strings. In Swift to avoid above unreliable extraction of characters - we have String Indices

startIndexstartIndex is the index of the first character.
endIndexendIndex is the index after the last character.

let testString = “hello”
testString[testString.startIndex]
// h
testString[testString.index(before: testString.endIndex)]
// o

Now:In above code example We didn’t use endIndex directly in subscript because endIndex is position out of bounds in our string. endIndex is the index after the last character. Hence we used .index(before: .endIndex)


let testString = "Cat!🐱!!"
let startIndex = testString.index(testString.startIndex, offsetBy: 3)
let endIndex = testString.index(testString.endIndex, offsetBy: -1)
let range: Range = startIndex..<endIndex
print(testString[range])
// Expected: !🐱!
// Actually returns: !🐱!

With Range of Indices, We did extract the substring that we expected reliably. In case of NSRange in objC we couldn’t extract it correctly. This will be the only discussion of major difference between Range and NSRange here and there are other more differences.

You must have noticed: In Swift we didn’t use substring(with: <Range <String.Index >)

Note:

substring(with:)’ is deprecated: Please use String slicing subscript.
In Swift 5 this function is deprecated and recommend us to use slicing subscript. We use testString[range]

NSRange don’t work in Swift subscript. We need to convert NSRange to Range.


let swiftRange = Range(oldNSRange, in: testString)
print(testString[swiftRange])

You might also like: AVAudioPlayer not playing any sound

You might also like: Blurry Pixel Font in SpriteKit bug

You might also like: How to Fix Warning Attempt To Present UIAlertController

More Articles

Recommended posts