Question or problem with Swift language programming:
In Objective-C the code to check for a substring in an NSString is:
NSString *string = @"hello Swift"; NSRange textRange =[string rangeOfString:@"Swift"]; if(textRange.location != NSNotFound) { NSLog(@"exists"); }
But how do I do this in Swift?
How to solve the problem:
Solution 1:
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
- 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.
Solution 2:
Extension way
Swift 4
extension String { func contains(find: String) -> Bool{ return self.range(of: find) != nil } func containsIgnoringCase(find: String) -> Bool{ return self.range(of: find, options: .caseInsensitive) != nil } } var value = "Hello world" print(value.contains("Hello")) // true print(value.contains("bo")) // false print(value.containsIgnoringCase(find: "hello")) // true print(value.containsIgnoringCase(find: "Hello")) // true print(value.containsIgnoringCase(find: "bo")) // false
Generally Swift 4 has contains method however it available from iOS 8.0+
Swift 3.1
You can write extension contains:
and containsIgnoringCase
for String
extension String { func contains(_ find: String) -> Bool{ return self.range(of: find) != nil } func containsIgnoringCase(_ find: String) -> Bool{ return self.range(of: find, options: .caseInsensitive) != nil } }
Older Swift version
extension String { func contains(find: String) -> Bool{ return self.rangeOfString(find) != nil } func containsIgnoringCase(find: String) -> Bool{ return self.rangeOfString(find, options: NSStringCompareOptions.CaseInsensitiveSearch) != nil } }
Example:
var value = "Hello world" print(value.contains("Hello")) // true print(value.contains("bo")) // false print(value.containsIgnoringCase("hello")) // true print(value.containsIgnoringCase("Hello")) // true print(value.containsIgnoringCase("bo")) // false
Solution 3:
From the docs, it seems that calling containsString()
on a String should work:
Swift’s String type is bridged seamlessly to Foundation’s NSString
class. If you are working with the Foundation framework in Cocoa or
Cocoa Touch, the entire NSString API is available to call on any
String value you create, in addition to the String features described
in this chapter. You can also use a String value with any API that
requires an NSString instance.
However, it doesn’t seem to work that way.
If you try to use someString.containsString(anotherString)
, you will get a compile time error that states 'String' does not contain a member named 'containsString'
.
So, you’re left with a few options, one of which is to explicitly bridge your String
to Objective-C by using bridgeToObjectiveC()
other two involve explicitly using an NSString
and the final one involves casting the String
to an NSString
By bridging, you’d get:
var string = "hello Swift" if string.bridgeToObjectiveC().containsString("Swift") { println("YES") }
By explicitly typing the string as an NSString
, you’d get:
var string: NSString = "hello Swift" if string.containsString("Swift") { println("YES") }
If you have an existing String
, you can initialize an NSString from it by using NSString(string:):
var string = "hello Swift" if NSString(string: string).containsString("Swift") { println("YES") }
And finally, you can cast an existing String
to an NSString
as below
var string = "hello Swift" if (string as NSString).containsString("Swift") { println("YES") }
Solution 4:
Another one. Supports case and diacritic options.
Swift 3.0
struct MyString { static func contains(_ text: String, substring: String, ignoreCase: Bool = true, ignoreDiacritic: Bool = true) -> Bool { var options = NSString.CompareOptions() if ignoreCase { _ = options.insert(NSString.CompareOptions.caseInsensitive) } if ignoreDiacritic { _ = options.insert(NSString.CompareOptions.diacriticInsensitive) } return text.range(of: substring, options: options) != nil } }
Usage
MyString.contains("Niels Bohr", substring: "Bohr") // true
iOS 9+
Case and diacritic insensitive function available since iOS 9.
if #available(iOS 9.0, *) { "Für Elise".localizedStandardContains("fur") // true }
Solution 5:
As of Xcode 7.1 and Swift 2.1 containsString()
is working fine for me.
let string = "hello swift" if string.containsString("swift") { print("found swift") }
Swift 4:
let string = "hello swift" if string.contains("swift") { print("found swift") }
And a case insensitive Swift 4 example:
let string = "Hello Swift" if string.lowercased().contains("swift") { print("found swift") }
Or using a case insensitive String
extension:
extension String { func containsIgnoreCase(_ string: String) -> Bool { return self.lowercased().contains(string.lowercased()) } } let string = "Hello Swift" let stringToFind = "SWIFT" if string.containsIgnoreCase(stringToFind) { print("found: \(stringToFind)") // found: SWIFT } print("string: \(string)") print("stringToFind: \(stringToFind)") // console output: found: SWIFT string: Hello Swift stringToFind: SWIFT