Different ways to check if a string contains another string in Swift
Table of Contents
Swift provides ways to check if a string contains another string, numbers, uppercased/lowercased string, or special characters. Each scenario might need a different method. I will visit some of them. In the end, you should be able to pick and adjust the one to suits your needs.
Check if a string contains another string
You can use range(of:options:)
, which finds and returns the range of the first occurrence of a given string within the string if found, and return a nil
if not.
func range<T>(of aString: T, options mask: CompareOptions = [], range searchRange: Range<Index>? = nil, locale: Locale? = nil) -> Range<Index>? where T : StringProtocol
If the range is not equals nil
, that's mean we find a substring within the string.
let c = "C"
let objc = "Objective-C"
objc.range(of: capitalC) != nil
// true
For this simple use case, range(of:options:)
might be overkill since it provides more options and parameters than we need. You can use an alternative method, contains(_:)
, which does the same thing but more concise.
public func contains<T>(_ other: T) -> Bool where T : StringProtocol
The method name and signature convey a clearer message than the previous one.
let c = "C"
let objc = "Objective-C"
objc.contains(c)
// true
You can easily support sarunw.com by checking out this sponsor.
AI Grammar: Correct grammar, spell check, check punctuation, and parphrase.
Check if a string contains a substring case insensitive.
If you want to check whether the string contains a given string by performing a case-insensitive search, you have two ways to do it.
As before you can use range(of:options:)
with .caseInsensitive
option.
let c = "c"
let objc = "Objective-C"
objc.range(of: c, options: .caseInsensitive) != nil
// true
Or you can use a more meaningful method name of localizedCaseInsensitiveContains(_:)
.
let c = "c"
let objc = "Objective-C"
objc.localizedCaseInsensitiveContains(c)
// true
Check if a string contains a number
To check whether a string contains a number or not, we use another form of the range-finding method, rangeOfCharacter(from:)
. This form finds and returns the range of the first character from a given character set. It accepts a character set parameter instead of a string.
You can declare character set like this:
let str = "SwiftUI 2.0"
let mySet = CharacterSet(["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"])
str.rangeOfCharacter(from: mySet) != nil
// true
CharacterSet
has many set operations. You can create a character set of digits with insert(charactersIn: String)
, which is less verbose.
let str = "SwiftUI 2.0"
var mySet = CharacterSet()
mySet.insert(charactersIn: "0123456789")
str.rangeOfCharacter(from: mySet) != nil
// true
But the two examples above might not cover all the cases if you want to support the non-English language. Here are examples of number in the Thai language
0-9 in Thai languages.
๐, ๑, ๒, ๓, ๔, ๕, ๖, ๗, ๘, ๙
So, instead of study all the possibilities in other languages. Apple provides a class variable, CharacterSet.decimalDigits
, that packs every digit for us.
var str = "SwiftUI 2.0"
let digitCharacters = CharacterSet.decimalDigits
str.rangeOfCharacter(from: digitCharacters) != nil
// true
Check if a string contains only a number
To check whether the string contains only numbers, we use the concept of set and CharacterSet.decimalDigits
together. For a string to contains only a number, all the characters in that string must be a subset of CharacterSet.decimalDigits
.
let numberOnly = "2021"
let str = "SwiftUI 2.0"
let digitsCharacters = CharacterSet.decimalDigits
CharacterSet(charactersIn: numberOnly).isSubset(of: digitsCharacters)
// true
CharacterSet(charactersIn: str).isSubset(of: digitsCharacters)
// false
Check if a string contains only alphanumerics
Apple provides an alphanumerics character set, CharacterSet.alphanumerics
. To find a string that contains only alphanumerics, we have to make sure there are no characters outside this set. To do that, we check a string against a converted set of CharacterSet.alphanumerics
(which means a set of non-alphanumeric characters).
If we find an occurrence of non-alphanumeric characters, the string is not alphanumerics.
If we don't find any occurrence of non-alphanumeric characters (range equals nil
), the string contains only alphanumerics.
let str = "Swift"
let numberOnly = "2021"
let space = "Hello World"
let specialCharacter = "$var"
let nonAlphanumericCharacters = CharacterSet.alphanumerics.inverted // <1>
let isAlphanumerics = numberOnly.rangeOfCharacter(from: nonAlphanumericCharacters) == nil // <2>
// true
let isAlphanumerics2 = space.rangeOfCharacter(from: nonAlphanumericCharacters) == nil // <3>
// false
let isAlphanumerics3 = specialCharacter.rangeOfCharacter(from: nonAlphanumericCharacters) == nil
// false
let isAlphanumerics4 = str.rangeOfCharacter(from: nonAlphanumericCharacters) == nil
// true
<1> We call .inverted
on CharacterSet.alphanumerics
which result in a set of non-alphanumeric characters.
<2> We find an occurrence of non-alphanumeric characters. If we can't find (nil
), the string is alphanumerics.
<3> If the return range does not equal to nil
, that means we find non-alphanumeric characters, so the string is not alphanumerics.
The rest of the examples are just a different set of character sets checking. I will jump right into the implementation.
Check if a string contains only letters
let str = "Swift"
let strWithNumbers = "Swift2"
let letterCharacters = CharacterSet.letters
let nonLetterCharacters = letterCharacters.inverted
let isLetter1 = str.rangeOfCharacter(from: nonLetterCharacters) == nil
// true, contains only letters
let isLetter2 = CharacterSet(charactersIn: strWithNumbers).isSubset(of: letterCharacters)
// false, not contains uppercase letters (2)
Check if a string contains uppercase letters
let lowercase = "swift"
let titlecase = "Swift"
let uppercaseLetters = CharacterSet.uppercaseLetters
lowercase.rangeOfCharacter(from: uppercaseLetters) != nil
// false, contains no uppercase letters
titlecase.rangeOfCharacter(from: uppercaseLetters) != nil
// true, contains uppercase letters
Check if a string contains lowercase letters
let titlecase = "Swift"
let uppercase = "SWIFT"
let lowercaseLetters = CharacterSet.lowercaseLetters
uppercase.rangeOfCharacter(from: lowercaseLetters) != nil
// false, contains no lowercase letters
titlecase.rangeOfCharacter(from: lowercaseLetters) != nil
// true, contains lowercase letters
Check if a string contains special characters
let str = "100%"
let specialCharacters: CharacterSet = ["$", "%", "&"] // <1>
str.rangeOfCharacter(from: specialCharacters) != nil
// true, contains special characters
<1> Define your special characters here.
User-level string search
As you can see, there are many ways to check if a string contains another string. One scenario that you might want to use is a user-level string search. When you do a user-level search, we don't want an exact match comparison because that would make the search less useful or difficult to use.
Here is an example search result from Safari, which is case and diacritic insensitive.
You could use range(of:options:)
with .caseInsensitive
and diacriticInsensitive
option.
let c = "c"
let capitalC = "C"
let cWithDiaCritic = "ć"
let objc = "Objective-C"
objc.range(of: c, options: [.caseInsensitive, .diacriticInsensitive]) != nil
// true
objc.range(of: cWithDiaCritic, options: [.caseInsensitive, .diacriticInsensitive]) != nil
// true
objc.range(of: capitalC, options: [.caseInsensitive, .diacriticInsensitive]) != nil
// true
Apple also provides a more meaningful method, localizedStandardContains
, which is the most appropriate method for doing user-level string searches, similar to how searches are done generally in the system.
/// Returns a Boolean value indicating whether the string contains the given
/// string, taking the current locale into account.
///
/// This is the most appropriate method for doing user-level string searches,
/// similar to how searches are done generally in the system. The search is
/// locale-aware, case and diacritic insensitive. The exact list of search
/// options applied may change over time.
@available(macOS 10.11, iOS 9.0, *)
public func localizedStandardContains<T>(_ string: T) -> Bool where T : StringProtocol
You can use it like this.
let c = "c"
let capitalC = "C"
let cWithDiaCritic = "ć"
let objc = "Objective-c"
capitalC.localizedStandardContains(cWithDiaCritic)
// true
objc.localizedStandardContains(c)
// true
objc.localizedStandardContains(capitalC)
// true
objc.localizedStandardContains(cWithDiaCritic)
// true
localizedStandardContains
is locale-aware, case, and diacritic insensitive. As you can see, c
, C
, and ć
are considered matched.
You can easily support sarunw.com by checking out this sponsor.
AI Grammar: Correct grammar, spell check, check punctuation, and parphrase.
Related Resources
Read more article about Swift, String, or see all available topic
Enjoy the read?
If you enjoy this article, you can subscribe to the weekly newsletter.
Every Friday, you'll get a quick recap of all articles and tips posted on this site. No strings attached. Unsubscribe anytime.
Feel free to follow me on Twitter and ask your questions related to this post. Thanks for reading and see you next time.
If you enjoy my writing, please check out my Patreon https://www.patreon.com/sarunw and become my supporter. Sharing the article is also greatly appreciated.
Become a patron Buy me a coffee Tweet ShareDifferent ways to compare string in Swift
String comparison is an essential operation for day to day job. Swift provides a few variations for this. We will visit them in this article.
Create a list of views in SwiftUI using ForEach
Part 1 in the series "Building Lists and Navigation in SwiftUI". We visit the first building block of any list view, content, and how to create them.