'Check if a String is alphanumeric in Swift

In Swift, how can I check if a String is alphanumeric, ie, if it contains only one or more alphanumeric characters [a-zA-Z0-9], excluding letters with diacritics, eg, é.



Solution 1:[1]

extension String {
    var isAlphanumeric: Bool {
        return !isEmpty && range(of: "[^a-zA-Z0-9]", options: .regularExpression) == nil
    }
}

"".isAlphanumeric        // false
"abc".isAlphanumeric     // true
"123".isAlphanumeric     // true
"ABC123".isAlphanumeric  // true
"iOS 9".isAlphanumeric   // false

Solution 2:[2]

A modern Swift 3 and 4 solution

extension String {

    func isAlphanumeric() -> Bool {
        return self.rangeOfCharacter(from: CharacterSet.alphanumerics.inverted) == nil && self != ""
    }

    func isAlphanumeric(ignoreDiacritics: Bool = false) -> Bool {
        if ignoreDiacritics {
            return self.range(of: "[^a-zA-Z0-9]", options: .regularExpression) == nil && self != ""
        }
        else {
            return self.isAlphanumeric()
        }
    }

}

Usage:

"".isAlphanumeric()         == false
"Hello".isAlphanumeric()    == true
"Hello 2".isAlphanumeric()  == false
"Hello3".isAlphanumeric()   == true

"Français".isAlphanumeric() == true
"Français".isAlphanumeric(ignoreDiacritics: true) == false

This works with languages other than English, allowing diacritic characters like è and á, etc. If you'd like to ignore these, use the flag "ignoreDiacritics: true".

Solution 3:[3]

I felt the accepted answer using regex was concrete but a rather heavy solution. You could check it this way also in Swift 3.0:

if yourString.rangeOfCharacter(from: CharacterSet.alphanumerics.inverted) != nil {
    return "Username can only contain numbers or digits"
}

Solution 4:[4]

extension String {
    /// Allows only `a-zA-Z0-9`
    public var isAlphanumeric: Bool {
        guard !isEmpty else {
            return false
        }
        let allowed = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"
        let characterSet = CharacterSet(charactersIn: allowed)
        guard rangeOfCharacter(from: characterSet.inverted) == nil else {
            return false
        }
        return true
    }
}

XCTAssertFalse("".isAlphanumeric)
XCTAssertFalse("climate change".isAlphanumeric)
XCTAssertFalse("Poüet".isAlphanumeric)
XCTAssertTrue("Hawking2018".isAlphanumeric)

Solution 5:[5]

The problem with the CharacterSet.alphanumerics CharacterSet is that it is more permissive than [a-zA-Z0-9]. It contains letters with diacritics, Eastern Arabic numerals, etc.

assert(["e", "E", "3"].allSatisfy({ CharacterSet.alphanumerics.contains($0) }))
assert(["ê", "É", "?"].allSatisfy({ CharacterSet.alphanumerics.contains($0) }))

You can build your own CharacterSet using only the specific 62 "alphanumeric" characters:

extension CharacterSet {
    
    static var alphanumeric62: CharacterSet {
        return lowercase26.union(uppercase26).union(digits10)
    }
    
    static var lowercase26: CharacterSet { CharacterSet(charactersIn: "a"..."z") }
    static var uppercase26: CharacterSet { CharacterSet(charactersIn: "A"..."Z") }
    static var digits10:    CharacterSet { CharacterSet(charactersIn: "0"..."9") }
    
}

assert(["e", "E", "3"].allSatisfy({ CharacterSet.alphanumeric62.contains($0) }))
assert(["ê", "É", "?"].allSatisfy({ CharacterSet.alphanumeric62.contains($0) == false }))

Then test your string against the inverse of that CharacterSet:

guard "string".rangeOfCharacter(from: CharacterSet.alphanumeric62.inverted) == nil else {
    fatalError()
}

Solution 6:[6]

This regex used to check that string contains atleast 1 alphabet + atleast 1 digit alongwith 8 characters.

"^(?=.*[A-Za-z])(?=.*\\d)[A-Za-z\\d]{8,}$"

Solution 7:[7]

extension String {  
   var isAlphaNumeric: Bool {
        let hasLetters = rangeOfCharacter(from: .letters, options: .numeric, range: nil) != nil
        let hasNumbers = rangeOfCharacter(from: .decimalDigits, options: .literal, range: nil) != nil
        let comps = components(separatedBy: .alphanumerics)
        return comps.joined(separator: "").count == 0 && hasLetters && hasNumbers  
   } 
}

Solution 8:[8]

Here's a succinct approach:

extension String {
    var isAlphanumeric: Bool {
       allSatisfy { $0.isLetter || $0.isNumber }
    }
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2
Solution 3 carbonr
Solution 4 neoneye
Solution 5 pkamb
Solution 6 Uma Madhavi
Solution 7 Sathish Kumar Gurunathan
Solution 8 rmp251