644

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?

TheNeil
  • 3,321
  • 2
  • 27
  • 52
Rajneesh071
  • 30,846
  • 15
  • 61
  • 74

27 Answers27

1260

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.
Sazzad Hissain Khan
  • 37,929
  • 33
  • 189
  • 256
Jens Wirth
  • 17,110
  • 4
  • 30
  • 33
  • I understand Swift is in beta, the amazing thing is so many devs seem to be switching to it on the first beta release. Hopefully they are filing radars. – zaph Jun 14 '14 at 15:51
  • 1
    I get 'error: 'String' does not have a member named 'rangeOfString' in playground on beta6. EDIT: because I hadn't 'import Foundation' – Ben Clayton Aug 30 '14 at 11:35
  • 14
    Apple's documentation says: `An NSRange structure giving the location and length in the receiver of the first occurrence of aString. Returns {NSNotFound, 0} if aString is not found or is empty (@"").` So maybe just checking for `nil` won't work properly. – Alex Sep 22 '14 at 09:01
  • 7
    string.lowercaseString.rangeOfString("swift").location != NSNotFound. Please read the documentation.. you will not get a nil object back. – TheCodingArt Oct 24 '14 at 02:33
  • 4
    @TheGamingArt Yes you will. Swift round-trips the whole thing for you automagically so that if the NSRange is `{NSNotFound, 0}` it is represented for you as nil. If it is an actual range, it is represented for you as a Swift Range (optional). Cool. – matt Nov 26 '14 at 18:53
  • This is the preferred method if you need to support iOS 7. containsString will only work in iOS 8 (or later, presumably) – zeeple Jan 27 '15 at 18:07
  • 4
    Grr. containsString is not in the docs, even as of Xcode 6.3.1. – Duncan C May 15 '15 at 14:49
  • 20
    @TheGoonie: This is not calling `NSString`'s `.rangeOfString()`. This is calling `String`'s `.rangeOfString()`, which is declared as `func rangeOfString(aString: String, options mask: NSStringCompareOptions = default, range searchRange: Range? = default, locale: NSLocale? = default) -> Range?` – newacct Jul 11 '15 at 20:32
  • Folks, I am new to learning swift. Aside from https://developer.apple.com/library/mac/documentation/Swift/Conceptual/Swift_Programming_Language/ and the epub available at swift.org.... what source do you prefer for api reference? For instance, to find the `rangeOfString` method somewhere in swift's api, how would one find and use it, instead of turning to google/sof? Thanks! – Cmag Jun 29 '16 at 20:31
  • @Cmag: The method belongs to the class NSString which is documented within [Apple's Foundation Framework Reference](https://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/) – Jens Wirth Jun 30 '16 at 06:55
  • In Swift 3, .lowercaseString has been renamed .lowercased() – adamek Nov 14 '16 at 15:03
  • In the case insensitive example, shouldn't "range(of:"swift")" also be lowercased? Like "range(of:"swift".lowercased())"? If the text was "Swift" I don't think your example would work or maybe I'm missing something. – Jason Fel Mar 31 '17 at 12:56
  • In Swift 3 println has been renamed print – kuzdu May 03 '17 at 11:07
  • Why not just `contains`? https://developer.apple.com/documentation/foundation/nsstring/1414563-contains –  Sep 10 '17 at 03:11
  • When checking multiple values (in a filter for example) you can do it like this `(string.range(of: "Swift") != nil)` – CherryNerd Dec 09 '18 at 21:36
  • usigng `"someString".range(of: query, options: .caseInsensitive)` is better – Siempay Mar 26 '19 at 09:36
  • Be careful. If you use this method the empty string is not contained in another string (which it is). – Joris Weimar Dec 05 '20 at 16:34
  • 1
    Got this error **Cannot convert value of type 'String' to expected argument type 'String.Element' (aka 'Character')** – mefahimrahman Mar 11 '21 at 12:37
  • FYI this requires `import Foundation`. This isn't built into Swift. – Patrick Sep 13 '21 at 09:25
  • 1
    contains is cheking a regexp!!! bear this in mind – Peter Lapisu Jan 23 '23 at 10:23
202

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
Community
  • 1
  • 1
Maxim Shoustin
  • 77,483
  • 27
  • 203
  • 225
  • 6
    to ignore case use return self.rangeOfString(find, options: NSStringCompareOptions.CaseInsensitiveSearch) != nil – masgar Nov 28 '15 at 10:54
  • 1
    No longer necessary unless you don't have `Foundation` around... `containsString` works fine. – Dan Rosenstark Mar 29 '16 at 19:21
  • 5
    for swift 3.0. Change to below: 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 } } – Michael Shang Sep 18 '16 at 10:18
  • For 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 } } – shokaveli Nov 07 '17 at 22:49
51

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")
}
webmagnets
  • 2,266
  • 3
  • 33
  • 60
Cezar
  • 55,636
  • 19
  • 86
  • 87
  • 4
    The last example (I haven't tried others) crashes for me on iOS 7 (device); Swift apps should run just fine on iOS 7. The error I get is `[__NSCFString containsString:]: unrecognized selector sent to instance`. Also, I can't find the method `containsString` in the dev docs to confirm if its new for iOS 8. – Jason Leach Jun 15 '14 at 03:32
  • Interesting. I only tested this on a playground. I will give it a try later when I'm on my computer. – Cezar Jun 15 '14 at 03:36
  • the third and fourth options are the only ones the compiler allowed. both crash for me in beta 4 in iOS 7. – Pouria Almassi Jul 25 '14 at 05:06
41

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
}
Evgenii
  • 36,389
  • 27
  • 134
  • 170
31

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
Murray Sagal
  • 8,454
  • 4
  • 47
  • 48
  • 3
    you need to `import Foundation`, otherwise this won't work. – Andrii Chernenko Mar 21 '16 at 15:55
  • Either `import UIKit` of `import Foundation` is required, at least with iOS 11 and Swift 4. – Murray Sagal Oct 30 '17 at 19:24
  • But that is case sensitive. How do you do comparison while ignoring case . Like in java String.equalsIgnoreCase(anotherString) ? – zulkarnain shah Nov 07 '17 at 05:11
  • @zulkarnainshah I added an example to the answer. – Murray Sagal Nov 07 '17 at 14:41
  • @MurraySagal Thats still not case insensitive search. You're converting the original string to lowercase and then comparing that explicitly with a lower case string. It will do the job, but thats not the ideal way to do that – zulkarnain shah Nov 07 '17 at 17:22
  • @zulkarnainshah I added another example showing that original values are not changed. I imagine that's pretty much how java's `equalsIgnoreCase()` or `containsIgnoreCase() is implemented. – Murray Sagal Nov 07 '17 at 22:45
23

In Swift 4.2

Use

func contains(_ str: String) -> Bool

Example

let string = "hello Swift"
let containsSwift = string.contains("Swift")
print(containsSwift) // prints true
Saranjith
  • 11,242
  • 5
  • 69
  • 122
16

> IN SWIFT 3.0

let str = "Hello Swift"
if str.lowercased().contains("Swift".lowercased()) {
    print("String Contains Another String")
} else {
    print("Not Exists")
}

Output

String Contains Another String
Ashok R
  • 19,892
  • 8
  • 68
  • 68
15

You can do this very easily in Swift using the code:

let string = "hello Swift";
let subString = (string as NSString).containsString("Swift")
if(subString){println("Exist")}
Anmol Kukreja
  • 110
  • 1
  • 8
10

Just an addendum to the answers here.

You can also do a local case insensitive test using:

 - (BOOL)localizedCaseInsensitiveContainsString:(NSString *)aString

Example:

    import Foundation

    var string: NSString  =  "hello Swift"
   if string.localizedCaseInsensitiveContainsString("Hello") {
    println("TRUE")
}

UPDATE

This is part of the Foundation Framework for iOS & Mac OS X 10.10.x and was part of 10.10 at Time of my original Posting.

Document Generated: 2014-06-05 12:26:27 -0700 OS X Release Notes Copyright © 2014 Apple Inc. All Rights Reserved.

OS X 10.10 Release Notes Cocoa Foundation Framework

NSString now has the following two convenience methods:

- (BOOL)containsString:(NSString *)str;

- (BOOL)localizedCaseInsensitiveContainsString:(NSString *)str;

markhunte
  • 6,805
  • 2
  • 25
  • 44
10

Of all of the answers here, I think they either don't work, or they're a bit of a hack (casting back to NSString). It's very likely that the correct answer to this has changed with the different beta releases.

Here is what I use:

let string: String = "hello Swift"
if string.rangeOfString("Swift") != nil
{
    println("exists")
}

The "!= nil" became required with Beta 5.

jeremywhuff
  • 2,911
  • 3
  • 29
  • 33
9

You can just do what you have mentioned:

import Foundation
...
string.contains("Swift");

From the docs:

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.

You need to import Foundation to bridge the NSString methods and make them available to Swift's String class.

NonCreature0714
  • 5,744
  • 10
  • 30
  • 52
manojlds
  • 290,304
  • 63
  • 469
  • 417
  • Not me, but no, it doesn't. – Cezar Jun 04 '14 at 12:28
  • yep. Tried in a Playground, in a Mac App and in an iOS app. Also tried in Playground importing Cocoa, UIKit, Foundation and all possible combinations of the three of them (except Cocoa/UIKit, which doesn't make sense) – Cezar Jun 04 '14 at 12:29
  • This is no longer the case as of Swift 1.2 – Kelvin Lau May 26 '15 at 10:40
9

Here is my first stab at this in the swift playground. I extend String by providing two new functions (contains and containsIgnoreCase)

extension String {
    func contains(other: String) -> Bool{
        var start = startIndex

        do{
            var subString = self[Range(start: start++, end: endIndex)]
            if subString.hasPrefix(other){
                return true
            }

        }while start != endIndex

        return false
    }

    func containsIgnoreCase(other: String) -> Bool{
        var start = startIndex

        do{
            var subString = self[Range(start: start++, end: endIndex)].lowercaseString
            if subString.hasPrefix(other.lowercaseString){
                return true
            }

        }while start != endIndex

        return false
    }
}

Use it like this

var sentence = "This is a test sentence"
sentence.contains("this")  //returns false
sentence.contains("This")  //returns true
sentence.containsIgnoreCase("this")  //returns true

"This is another test sentence".contains(" test ")    //returns true

I'd welcome any feedback :)

Ken
  • 107
  • 1
  • Next step: Make this a generic function which works on all Collection's :-) E.g. checkout the startsWith() builtin function. In the 'ignore case' variant, only lowercase the strings once (let lc = other.lowercaseString before the do) – hnh Jul 04 '14 at 11:07
6

Here you are:

let s = "hello Swift"
if let textRange = s.rangeOfString("Swift") {
    NSLog("exists")
}
Stéphane de Luca
  • 12,745
  • 9
  • 57
  • 95
  • Sometime you might need a compact form as follows: let rangeIfExists = string.rangeOfString("Swift") ?? false which either returns false as a boolean if it's not contained or the NSRange otherwise – Stéphane de Luca Jul 18 '15 at 16:39
5

You don't need to write any custom code for this. Starting from the 1.2 version Swift has already had all the methods you need:

  • getting string length: count(string);
  • checking if string contains substring: contains(string, substring);
  • checking if string starts with substring: startsWith(string, substring)
  • and etc.
Max Ivashkevich
  • 366
  • 4
  • 10
5

In Swift 3

if((a.range(of: b!, options: String.CompareOptions.caseInsensitive, range: nil, locale: nil)) != nil){
    print("Done")
}
Petter Friberg
  • 21,252
  • 9
  • 60
  • 109
Marie Amida
  • 556
  • 1
  • 5
  • 14
5

Swift 5, case insensitive:

if string.localizedLowercase.contains("swift".localizedLowercase){
    // your code here
}
Md. Ibrahim Hassan
  • 5,359
  • 1
  • 25
  • 45
S Lareau
  • 159
  • 1
  • 5
4

Here you go! Ready for Xcode 8 and Swift 3.

import UIKit

let mString = "This is a String that contains something to search."
let stringToSearchUpperCase = "String"
let stringToSearchLowerCase = "string"

mString.contains(stringToSearchUpperCase) //true
mString.contains(stringToSearchLowerCase) //false
mString.lowercased().contains(stringToSearchUpperCase) //false
mString.lowercased().contains(stringToSearchLowerCase) //true
Carlitos
  • 343
  • 5
  • 7
3

string.containsString is only available in 10.10 Yosemite (and probably iOS8). Also bridging it to ObjectiveC crashes in 10.9. You're trying to pass a NSString to NSCFString. I don't know the difference, but I can say 10.9 barfs when it executes this code in a OS X 10.9 app.

Here are the differences in Swift with 10.9 and 10.10: https://developer.apple.com/library/prerelease/mac/documentation/General/Reference/APIDiffsMacOSX10_10SeedDiff/index.html containsString is only available in 10.10

Range of String above works great on 10.9. I am finding developing on 10.9 is super stable with Xcode beta2. I don't use playgrounds through or the command line version of playgrounds. I'm finding if the proper frameworks are imported the autocomplete is very helpful.

Goodtime
  • 111
  • 3
3

Xcode 8/Swift 3 version:

let string = "hello Swift"

if let range = string.range(of: "Swift") {
    print("exists at range \(range)")
} else {
    print("does not exist")
}

if let lowercaseRange = string.lowercased().range(of: "swift") {
    print("exists at range \(lowercaseRange)")
} else {
    print("does not exist")
}

You can also use contains:

string.contains("swift") // false
string.contains("Swift") // true
JAL
  • 41,701
  • 23
  • 172
  • 300
3

Swift 4 way to check for substrings, including the necessary Foundation (or UIKit) framework import:

import Foundation // or UIKit

let str = "Oh Canada!"

str.contains("Can") // returns true

str.contains("can") // returns false

str.lowercased().contains("can") // case-insensitive, returns true

Unless Foundation (or UIKit) framework is imported, str.contains("Can") will give a compiler error.


This answer is regurgitating manojlds's answer, which is completely correct. I have no idea why so many answers go through so much trouble to recreate Foundation's String.contains(subString: String) method.

E_net4
  • 27,810
  • 13
  • 101
  • 139
NonCreature0714
  • 5,744
  • 10
  • 30
  • 52
3

With and new syntax in swift 4 you can just

string.contains("Swift 4 is the best")

string is your string variable

100tomer
  • 137
  • 1
  • 10
2

Check if it contains 'Hello'

let s = "Hello World"

if s.rangeOfString("Hello") != nil {
    print("Yes it contains 'Hello'")
}
2

If you want to check that one String contains another Sub-String within it or not you can check it like this too,

var name = String()  
name = "John has two apples." 

Now, in this particular string if you want to know if it contains fruit name 'apple' or not you can do,

if name.contains("apple") {  
  print("Yes , it contains fruit name")    
} else {    
  print("it does not contain any fruit name")    
}    

Hope this works for you.

Tushar Moradiya
  • 780
  • 1
  • 6
  • 13
1
// Search string exist in employee name finding.
var empName:NSString! = employeeDetails[filterKeyString] as NSString

Case sensitve search.
let rangeOfSearchString:NSRange! = empName.rangeOfString(searchString, options: NSStringCompareOptions.CaseInsensitiveSearch)

// Not found.
if rangeOfSearchString.location != Foundation.NSNotFound
{
    // search string not found in employee name.
}
// Found
else
{
    // search string found in employee name.
}
Ramzi Khahil
  • 4,932
  • 4
  • 35
  • 69
abhi
  • 563
  • 6
  • 9
0

In iOS 8 and newer, you can use these two NSString methods:

@availability(iOS, introduced=8.0)
func containsString(aString: String) -> Bool

@availability(iOS, introduced=8.0)
func localizedCaseInsensitiveContainsString(aString: String) -> Bool
Rudolf Adamkovič
  • 31,030
  • 13
  • 103
  • 118
  • What? it looks like it is not available? in the version that comes with xcode 6.1 – Ali Dec 02 '14 at 17:15
0

I've found a couple of interesting use cases. These variants make use of the rangeOfString method and I include the equality example to show how one might best use the search and comparison features of Strings in Swift 2.0

//In viewDidLoad() I assign the current object description (A Swift String) to self.loadedObjectDescription
self.loadedObjectDescription = self.myObject!.description

Later after I've made changes to self.myObject, I can refer to the following string comparison routines (setup as lazy variables that return a Bool). This allows one to check the state at any time.

lazy var objectHasChanges : Bool = {
        guard self.myObject != nil else { return false }
        return !(self.loadedObjectDescription == self.myObject!.description)
    }()

A variant of this happens when sometimes I need to analyze a missing property on that object. A string search allows me to find a particular substring being set to nil (the default when an object is created).

    lazy var isMissingProperty : Bool = {
        guard self.myObject != nil else { return true }
        let emptyPropertyValue = "myProperty = nil"
        return (self.myObject!.description.rangeOfString(emptyPropertyValue) != nil) ? true : false
    }()
Tommie C.
  • 12,895
  • 5
  • 82
  • 100
0

SWIFT 4 is very easy!!

if (yourString.contains("anyThing")) {
   print("Exist")
}
user2878850
  • 2,446
  • 1
  • 18
  • 22
oscar castellon
  • 3,048
  • 30
  • 19
  • 1
    How is this any different to several of the other answers here? – Ashley Mills Aug 19 '18 at 16:55
  • 1
    `$ swift Welcome to Apple Swift version 4.2 (swiftlang-1000.11.37.1 clang-1000.11.45.1). Type :help for assistance. 1> print ("Ping") Ping 2> Print ("Ping") error: repl.swift:2:1: error: use of unresolved identifier 'Print' Print ("Ping") ^~~~~ ` By providing an untested answer that does't work. Print != print. – Fred Gannett Oct 29 '18 at 09:29