Swift Startswith Method

Swift startsWith method?

use hasPrefix instead of startsWith.

Example:

"hello dolly".hasPrefix("hello")  // This will return true
"hello dolly".hasPrefix("abc") // This will return false

Swift: String starts(with:) vs hasPrefix

String.hasPrefix() is implemented in StringLegacy.swift as

extension String {

public func hasPrefix(_ prefix: String) -> Bool {
if _fastPath(self._guts.isNFCFastUTF8 && prefix._guts.isNFCFastUTF8) {
guard prefix._guts.count <= self._guts.count else { return false }
return prefix._guts.withFastUTF8 { nfcPrefix in
let prefixEnd = nfcPrefix.count
return self._guts.withFastUTF8(range: 0..<prefixEnd) { nfcSlicedSelf in
return _binaryCompare(nfcSlicedSelf, nfcPrefix) == 0
}
}
}

return starts(with: prefix)
}

}

which means (if I understand it correctly): If both the string and the prefix candidate use a UTF-8 based storage then the UTF-8 bytes are compared directly. Otherwise it falls back to starts(with:) and does a Character based comparison.

So there is no difference in the result, but hasPrefix() is optimized for native Swift strings.

Note: This is the from the master (Swift 5) branch, the situation might be different in earlier versions.

How to check what a String starts with (prefix) or ends with (suffix) in Swift

Updated for Swift 4

Checking what a String starts with and ends with

You can use the hasPrefix(_:) and hasSuffix(_:) methods to test equality with another String.

let str = "Hello, playground"

if str.hasPrefix("Hello") { // true
print("Prefix exists")
}

if str.hasSuffix("ground") { // true
print("Suffix exists")
}

Getting the Actual Prefix and Suffix Substrings

In order to get the actual prefix or suffix substring, you can use one of the following methods. I recommend the first method for it's simplicity. All methods use str as

let str = "Hello, playground"

Method 1: (Recommended) prefix(Int) and suffix(Int)

let prefix = String(str.prefix(5)) // Hello
let suffix = String(str.suffix(6)) // ground

This is the better method in my opinion. Unlike the methods 2 and 3 below, this method will not crash if the indexes go out of bounds. It will just return all the characters in the string.

let prefix = String(str.prefix(225)) // Hello, playground
let suffix = String(str.suffix(623)) // Hello, playground

Of course, sometimes crashes are good because they let you know there is a problem with your code. So consider the second method below as well. It will throw an error if the index goes out of bounds.

Method 2: prefix(upto:) and suffix(from:)

Swift String indexes are tricky because they have to take into account special characters (like emoji). However once you get the index it is easy to get the prefix or suffix. (See my other answer on String.Index.)

let prefixIndex = str.index(str.startIndex, offsetBy: 5)
let prefix = String(str.prefix(upTo: prefixIndex)) // Hello

let suffixIndex = str.index(str.endIndex, offsetBy: -6)
let suffix = String(str.suffix(from: suffixIndex)) // ground

If you want to guard against going out of bounds, you can make an index using limitedBy (again, see this answer).

Method 3: subscripts

Since String is a collection, you can use subscripts to get the prefix and suffix.

let prefixIndex = str.index(str.startIndex, offsetBy: 5)
let prefix = String(str[..<prefixIndex]) // Hello

let suffixIndex = str.index(str.endIndex, offsetBy: -6)
let suffix = String(str[suffixIndex...]) // ground

Further Reading

  • Strings and Characters documentation

How do I check if a string contains another string in Swift?

You can do exactly the same call with Swift:

Swift 4 & Swift 5

In Swift 4 String is a collection of Character values, it wasn't like this in Swift 2 and 3, so you can use this more concise code1:

let string = "hello Swift"
if string.contains("Swift") {
print("exists")
}

Swift 3.0+

var string = "hello Swift"

if string.range(of:"Swift") != nil {
print("exists")
}

// alternative: not case sensitive
if string.lowercased().range(of:"swift") != nil {
print("exists")
}

Older Swift

var string = "hello Swift"

if string.rangeOfString("Swift") != nil{
println("exists")
}

// alternative: not case sensitive
if string.lowercaseString.rangeOfString("swift") != nil {
println("exists")
}

I hope this is a helpful solution since some people, including me, encountered some strange problems by calling containsString().1

PS. Don't forget to import Foundation

Footnotes

  1. Just remember that using collection functions on Strings has some edge cases which can give you unexpected results, e. g. when dealing with emojis or other grapheme clusters like accented letters.

Why isn't there a formSubtracting() method in Swift for Sets

subtract(_:) is what you are looking for:

Removes the elements of the given set from this set.

Example:

var mySet: Set = [1, 2, 3, 4, 5]
let anotherSet : Set = [2, 4, 6, 8]
mySet.subtract(anotherSet)
print(mySet) // [3, 1, 5]

There is also a variant which takes another sequence (of the same element type) as the argument, e.g. an array:

var mySet: Set = [1, 2, 3, 4, 5]
let anotherSequence = [2, 4, 6, 8]
mySet.subtract(anotherSequence)
print(mySet) // [3, 1, 5]

How to use `string.startsWith()` method ignoring the case?

Use toUpperCase() or toLowerCase() to standardise your string before testing it.

Contains where syntax different when placed in own method in Swift

The error is misleading.

In the function the parameter newmessage is non-optional so you have to remove the exclamation mark (and the enclosing parentheses – also around the if condition – anyway).

let aboutLocation = self.locationWords.contains(where: {$0.caseInsensitiveCompare(newmessage) == .orderedSame})
if aboutLocation { ...

But you can indeed omit the where parameter label using trailing closure syntax

let aboutLocation = locationWords.contains{ $0.caseInsensitiveCompare(newmessage) == .orderedSame }

How to check if a string contains another string but a character can vary?

You can use a regular expression "He[a-z]{2}o World". This would require any two lowercase letters between e and o:

let sentence = "Hello World"
let pattern = "He[a-z]{2}o World"
if sentence.range(of: pattern, options: .regularExpression) != nil {
print(true)
}

How does String substring work in Swift

Sample Image

All of the following examples use

var str = "Hello, playground"

Swift 4

Strings got a pretty big overhaul in Swift 4. When you get some substring from a String now, you get a Substring type back rather than a String. Why is this? Strings are value types in Swift. That means if you use one String to make a new one, then it has to be copied over. This is good for stability (no one else is going to change it without your knowledge) but bad for efficiency.

A Substring, on the other hand, is a reference back to the original String from which it came. Here is an image from the documentation illustrating that.

No copying is needed so it is much more efficient to use. However, imagine you got a ten character Substring from a million character String. Because the Substring is referencing the String, the system would have to hold on to the entire String for as long as the Substring is around. Thus, whenever you are done manipulating your Substring, convert it to a String.

let myString = String(mySubstring)

This will copy just the substring over and the memory holding old String can be reclaimed. Substrings (as a type) are meant to be short lived.

Another big improvement in Swift 4 is that Strings are Collections (again). That means that whatever you can do to a Collection, you can do to a String (use subscripts, iterate over the characters, filter, etc).

The following examples show how to get a substring in Swift.

Getting substrings

You can get a substring from a string by using subscripts or a number of other methods (for example, prefix, suffix, split). You still need to use String.Index and not an Int index for the range, though. (See my other answer if you need help with that.)

Beginning of a string

You can use a subscript (note the Swift 4 one-sided range):

let index = str.index(str.startIndex, offsetBy: 5)
let mySubstring = str[..<index] // Hello

or prefix:

let index = str.index(str.startIndex, offsetBy: 5)
let mySubstring = str.prefix(upTo: index) // Hello

or even easier:

let mySubstring = str.prefix(5) // Hello

End of a string

Using subscripts:

let index = str.index(str.endIndex, offsetBy: -10)
let mySubstring = str[index...] // playground

or suffix:

let index = str.index(str.endIndex, offsetBy: -10)
let mySubstring = str.suffix(from: index) // playground

or even easier:

let mySubstring = str.suffix(10) // playground

Note that when using the suffix(from: index) I had to count back from the end by using -10. That is not necessary when just using suffix(x), which just takes the last x characters of a String.

Range in a string

Again we simply use subscripts here.

let start = str.index(str.startIndex, offsetBy: 7)
let end = str.index(str.endIndex, offsetBy: -6)
let range = start..<end

let mySubstring = str[range] // play

Converting Substring to String

Don't forget, when you are ready to save your substring, you should convert it to a String so that the old string's memory can be cleaned up.

let myString = String(mySubstring)

Using an Int index extension?

I'm hesitant to use an Int based index extension after reading the article Strings in Swift 3 by Airspeed Velocity and Ole Begemann. Although in Swift 4, Strings are collections, the Swift team purposely hasn't used Int indexes. It is still String.Index. This has to do with Swift Characters being composed of varying numbers of Unicode codepoints. The actual index has to be uniquely calculated for every string.

I have to say, I hope the Swift team finds a way to abstract away String.Index in the future. But until then, I am choosing to use their API. It helps me to remember that String manipulations are not just simple Int index lookups.



Related Topics



Leave a reply



Submit