How to find out if letter is Alphanumeric or Digit in Swift
Asked Answered
U

5

39

I want to count the number of letters, digits and special characters in the following string:

let phrase = "The final score was 32-31!"

I tried:

for tempChar in phrase {
    if (tempChar >= "a" && tempChar <= "z") {
       letterCounter++
    }
// etc.

but I'm getting errors. I tried all sorts of other variations on this - still getting error - such as:

could not find an overload for '<=' that accepts the supplied arguments

Unbuckle answered 1/7, 2014 at 4:51 Comment(0)
S
58

For Swift 5 see rustylepord's answer.

Update for Swift 3:

let letters = CharacterSet.letters
let digits = CharacterSet.decimalDigits

var letterCount = 0
var digitCount = 0

for uni in phrase.unicodeScalars {
    if letters.contains(uni) {
        letterCount += 1
    } else if digits.contains(uni) {
        digitCount += 1
    }
}

(Previous answer for older Swift versions)

A possible Swift solution:

var letterCounter = 0
var digitCount = 0
let phrase = "The final score was 32-31!"
for tempChar in phrase.unicodeScalars {
    if tempChar.isAlpha() {
        letterCounter++
    } else if tempChar.isDigit() {
        digitCount++
    }
}

Update: The above solution works only with characters in the ASCII character set, i.e. it does not recognize Ä, é or ø as letters. The following alternative solution uses NSCharacterSet from the Foundation framework, which can test characters based on their Unicode character classes:

let letters = NSCharacterSet.letterCharacterSet()
let digits = NSCharacterSet.decimalDigitCharacterSet()

var letterCount = 0
var digitCount = 0

for uni in phrase.unicodeScalars {
    if letters.longCharacterIsMember(uni.value) {
        letterCount++
    } else if digits.longCharacterIsMember(uni.value) {
        digitCount++
    }
}

Update 2: As of Xcode 6 beta 4, the first solution does not work anymore, because the isAlpha() and related (ASCII-only) methods have been removed from Swift. The second solution still works.

Searle answered 1/7, 2014 at 5:4 Comment(10)
yep, that's perfect - how the hell did you find out about "isAlpha" and "isDigit"????? :-) I didn't even know those existed. (Seriously - did you look them up or did you already run into them in prior travels?)Unbuckle
@sirab333: isalpha() and friends are well known in C, see e.g. developer.apple.com/library/ios/documentation/System/Conceptual/…. So I had "only" to figure out how to use them from Swift. - But note that this works only for ASCII characters. It does not recognize letters from "foreign languages" such as "ä", "è" or "ø".Searle
and it recognizes + and - as digitNordstrom
Interesting. I never had any C, C#, C++ or any other C - I jumped right into Objective-C and never looked back. All in all then, would you say this is a "legitimate" solution - or is there a more "pure" Swift-only way to do this, without any C involved?Unbuckle
@ChristianDietrich: Are you sure? My test does not confirm this.Searle
@sirab333: isAlpha() is a Swift function (which has the same name as the corresponding C macro). - I have not found anything else in native Swift. But NSCharacterSet from the Foundation frameworks is probably the better tool. I have updated the answer with an example.Searle
@MartinR no i confused that with String("+").toInt() which actually does thatNordstrom
isAlpha and isDigit are not methods of UnicodeScalarPrittleprattle
@Gerry: Yes, that's what I added as "Update 2:" to my answer.Searle
@Warpzit: Yes, quite a lot changed with Swift 3. I have updated the answer, thanks for the feedback.Searle
A
5

Use the values of unicodeScalars

let phrase = "The final score was 32-31!"
var letterCounter = 0, digitCounter = 0
for scalar in phrase.unicodeScalars {
    let value = scalar.value
    if (value >= 65 && value <= 90) || (value >= 97 && value <= 122) {++letterCounter}
    if (value >= 48 && value <= 57) {++digitCounter}
}
println(letterCounter)
println(digitCounter)
Aglow answered 15/10, 2014 at 15:34 Comment(0)
F
5

For Swift 5 you can do the following for simple strings, but be vigilant about handling characters like "1️⃣" , "④" these would be treated as numbers as well.

let phrase = "The final score was 32-31!"

var numberOfDigits = 0;
var numberOfLetters = 0;
var numberOfSymbols = 0;

phrase.forEach {

    if ($0.isNumber) {
        numberOfDigits += 1;
    }
    else if ($0.isLetter)  {
        numberOfLetters += 1
    }
    else if ($0.isSymbol || $0.isPunctuation || $0.isCurrencySymbol || $0.isMathSymbol) {
        numberOfSymbols += 1;
    }
}

print(#"\#(numberOfDigits)  || \#(numberOfLetters) || \#(numberOfSymbols)"#);
Falsetto answered 6/9, 2019 at 15:9 Comment(0)
T
1

In case you only need one information (letter or number or sign) you can do it in one line:

let phrase = "The final score was 32-31!"

let count = phrase.filter{ $0.isLetter }.count
print(count) // "16\n"

But doing phrase.filter several times is inefficient because it loops through the whole string.

Trilinear answered 20/4, 2021 at 18:55 Comment(0)
A
0

I've created a short extension for letter and digits count for a String

extension String {
  var letterCount : Int {
    return self.unicodeScalars.filter({ CharacterSet.letters.contains($0) }).count
  }

  var digitCount : Int {
   return self.unicodeScalars.filter({ CharacterSet.decimalDigits.contains($0) }).count
  }
}

or a function to get a count for any CharacterSet you put in

extension String {    
  func characterCount(for set: CharacterSet) -> Int {
    return self.unicodeScalars.filter({ set.contains($0) }).count
  }
}

usage:

let phrase = "the final score is 23-13!"
let letterCount = phrase.characterCount(for: .letters)
Aether answered 11/4, 2018 at 10:10 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.