27

I'm trying to check whether a specific string contains letters or not.

So far I've come across NSCharacterSet.letterCharacterSet() as a set of letters, but I'm having trouble checking whether a character in that set is in the given string. When I use this code, I get an error stating:

'Character' is not convertible to 'unichar'

For the following code:

for chr in input{
    if letterSet.characterIsMember(chr){
        return "Woah, chill out!"
    }
}
narner
  • 2,908
  • 3
  • 26
  • 63
qmlowery
  • 535
  • 2
  • 5
  • 7
  • Compare [What is the best way to determine if a string contains a character from a set in Swift](http://stackoverflow.com/questions/28486138/what-is-the-best-way-to-determine-if-a-string-contains-a-character-from-a-set-in) ? – Martin R Apr 08 '15 at 17:48
  • @MartinR Why "compare"? It looks like a pretty solid duplicate to me. – Sergey Kalinichenko Apr 08 '15 at 18:04
  • **Swift 5+** This is definitely not (or no longer) a duplicate.... The linked question asks to check against a predefined list of characters. This asks if the string contains letters. This can now be done with a one liner and built-in Swift method: `yourString.allSatisfy { $0.isLetter }` – Eric Jun 15 '22 at 02:50

3 Answers3

58

You can use NSCharacterSet in the following way :

let letters = NSCharacterSet.letters

let phrase = "Test case"
let range = phrase.rangeOfCharacter(from: characterSet)

// range will be nil if no letters is found
if let test = range {
    println("letters found")
}
else {
   println("letters not found")
}

Or you can do this too :

func containsOnlyLetters(input: String) -> Bool {
   for chr in input {
      if (!(chr >= "a" && chr <= "z") && !(chr >= "A" && chr <= "Z") ) {
         return false
      }
   }
   return true
}

In Swift 2:

func containsOnlyLetters(input: String) -> Bool {
   for chr in input.characters {
      if (!(chr >= "a" && chr <= "z") && !(chr >= "A" && chr <= "Z") ) {
         return false
      }
   }
   return true
}

It's up to you, choose a way. I hope this help you.

Theo
  • 3,826
  • 30
  • 59
Victor Sigler
  • 23,243
  • 14
  • 88
  • 105
  • Your second code block does not compile in Swift, you have to use double-quotes. – Martin R Apr 08 '15 at 17:29
  • I tried the first solution, and it worked, though I'm not sure I understand the `if let test = range` line. – qmlowery Apr 09 '15 at 06:01
  • 1
    @user199470 the `if let test = range` it's the way to test if `range` isn't `nil` , nothing else, in which case it's only letters what it contains. – Victor Sigler Apr 09 '15 at 13:17
  • 2
    the first solution is elegant. – nyxee May 20 '17 at 23:20
  • 2
    It should be made clear that while the first example, using `NSCharacterSet`, works with non-English letters as well (German, Spanish, even Hebrew, and hopefully Arabic, too), the second only works with english letters, which may not be what international users would expect. – Thomas Tempelmann May 28 '17 at 10:34
  • 3
    Swift 4: `if let _ = string.rangeOfCharacter(from: NSCharacterSet.letters) { }` – Alexander Yakovlev Dec 27 '18 at 19:04
8

You should use the Strings built in range functions with NSCharacterSet rather than roll your own solution. This will give you a lot more flexibility too (like case insensitive search if you so desire).

let str = "Hey this is a string"
let characterSet = NSCharacterSet(charactersInString: "aeiou")

if let _ = str.rangeOfCharacterFromSet(characterSet, options: .CaseInsensitiveSearch) {
    println("true")
}
else {
    println("false")
}

Substitute "aeiou" with whatever letters you're looking for.

A less flexible, but fun swift note all the same, is that you can use any of the functions available for Sequences. So you can do this:

contains("abc", "c")

This of course will only work for individual characters, and is not flexible and not recommended.

Jarsen
  • 7,432
  • 6
  • 27
  • 26
4

The trouble with .characterIsMember is that it takes a unichar (a typealias for UInt16).

If you iterate your input using the utf16 view of the string, it will work:

let set = NSCharacterSet.letterCharacterSet()
for chr in input.utf16 {
    if set.characterIsMember(chr) {
        println("\(chr) is a letter")
    }
}

You can also skip the loop and use the contains algorithm if you only want to check for presence/non-presence:

if contains(input.utf16, { set.characterIsMember($0) }) {
    println("contains letters")
}
Airspeed Velocity
  • 40,491
  • 8
  • 113
  • 118