Check if a string contains at least a upperCase letter, a digit, or a special character in Swift?

23,557

Solution 1

Simply replace your RegEx rule [A-Z]+ with .*[A-Z]+.* (and other RegEx rules as well)

Rules

[A-Z]+ matches only strings with all characters capitalized

Examples: AVATAR, AVA, TAR, AAAAAA
Won't work: AVATAr

.* matches all strings (0+ characters)

Examples: 1, 2, AVATAR, AVA, TAR, a, b, c

.*[A-Z]+.* matches all strings with at least one capital letter

Examples: Avatar, avataR, aVatar

Explanation:

I. .* will try to match 0 or more of anything
II. [A-Z]+ will require at least one capital letter (because of the +)
III. .* will try to match 0 or more of anything

Avatar [empty | "A" | "vatar"]
aVatar ["a" | "V" | "atar"]
aVAtar ["a" | "VA" | "tar"]

Working Code

func checkTextSufficientComplexity(var text : String) -> Bool{


    let capitalLetterRegEx  = ".*[A-Z]+.*"
    var texttest = NSPredicate(format:"SELF MATCHES %@", capitalLetterRegEx)
    var capitalresult = texttest!.evaluateWithObject(text)
    println("\(capitalresult)")


    let numberRegEx  = ".*[0-9]+.*"
    var texttest1 = NSPredicate(format:"SELF MATCHES %@", numberRegEx)
    var numberresult = texttest1!.evaluateWithObject(text)
    println("\(numberresult)")


    let specialCharacterRegEx  = ".*[!&^%$#@()/]+.*"
    var texttest2 = NSPredicate(format:"SELF MATCHES %@", specialCharacterRegEx)

    var specialresult = texttest2!.evaluateWithObject(text)
    println("\(specialresult)")

    return capitalresult || numberresult || specialresult

}

Examples:

checkTextSufficientComplexity("Avatar") // true || false || false
checkTextSufficientComplexity("avatar") // false || false || false
checkTextSufficientComplexity("avatar1") // false || true || false
checkTextSufficientComplexity("avatar!") // false || false || true

Solution 2

Here is a concise version of Joshuas answer in Swift 3, assuming that all validations must be fulfilled.

func validate(password: String) -> Bool {
    let capitalLetterRegEx  = ".*[A-Z]+.*"
    let texttest = NSPredicate(format:"SELF MATCHES %@", capitalLetterRegEx)
    guard texttest.evaluate(with: password) else { return false }

    let numberRegEx  = ".*[0-9]+.*"
    let texttest1 = NSPredicate(format:"SELF MATCHES %@", numberRegEx)
    guard texttest1.evaluate(with: password) else { return false }

    let specialCharacterRegEx  = ".*[!&^%$#@()/_*+-]+.*"
    let texttest2 = NSPredicate(format:"SELF MATCHES %@", specialCharacterRegEx)
    guard texttest2.evaluate(with: password) else { return false }

    return true
}

Solution 3

Another alternate solution.

You can do all the check using one regular expression.

RegExp: ^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[$@$!%*?&])[A-Za-z\\d$@$!%*?&]{8,}

You can use this as mention below:

//Minimum 8 characters at least 1 Uppercase Alphabet, 1 Lowercase Alphabet, 1 Number and 1 Special Character:
let regex = "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[$@$!%*?&])[A-Za-z\\d$@$!%*?&]{8,}"
let isMatched = NSPredicate(format:"SELF MATCHES %@", regex).evaluate(with: yourTextField.text)
if(isMatched  == true) {
    // Do your stuff ..
}  else {
    // Show Error Message.
}

Solution 4

At least 1 Uppercase, 1 Lowercase, 1 Special Characters, 1 Number, and Total 8 Characters.

To support all special characters listed in https://www.owasp.org/index.php/Password_special_characters

!"#$%&'()*+,-./:;<=>?@[]^_`{|}~

extension String {
    func isValidPassword() -> Bool {
        //let passwordRegex = "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[ !\"\\\\#$%&'()*+,-./:;<=>?@\\[\\]^_`{|}~])[A-Za-z\\d !\"\\\\#$%&'()*+,-./:;<=>?@\\[\\]^_`{|}~]{8,}"
        //safe to escape all regex chars
        let passwordRegex = "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[ !\"\\\\#$%&'\\(\\)\\*+,\\-\\./:;<=>?@\\[\\]^_`\\{|\\}~])[A-Za-z\\d !\"\\\\#$%&'\\(\\)\\*+,\\-\\./:;<=>?@\\[\\]^_`\\{|\\}~]{8,}"
        return NSPredicate(format: "SELF MATCHES %@", passwordRegex).evaluate(with: self)
    }
}
Share:
23,557

Related videos on Youtube

Anish Parajuli 웃
Author by

Anish Parajuli 웃

Data Science Student at RMIT University

Updated on September 29, 2020

Comments

  • Anish Parajuli 웃
    Anish Parajuli 웃 over 3 years

    I am trying to create a method that finds whether a string contains a number , Upper case letter and a special character using regular expression as below

     func checkTextSufficientComplexity(var text : String) -> Bool{
    
    
                let capitalLetterRegEx  = "[A-Z]+"
                var texttest = NSPredicate(format:"SELF MATCHES %@", capitalLetterRegEx)
                var capitalresult = texttest.evaluateWithObject("AniP")
                println("\(capitalresult)")
    
    
                let numberRegEx  = "[0-9]+"
                var texttest1 = NSPredicate(format:"SELF MATCHES %@", numberRegEx)
                var numberresult = texttest1.evaluateWithObject(text)
                println("\(numberresult)")
    
    
                let specialCharacterRegEx  = "[.*&^%$#@()/]+"
                var texttest2 = NSPredicate(format:"SELF MATCHES %@", numberRegEx)
    
                var specialresult = texttest2.evaluateWithObject(text)
                println("\(specialresult)")
    
               return capitalresult && numberresult && specialresult
    
        }
    

    The problem is the below regular expression [A-Z]+ returns true for only e.g AVATAR and returns false for Avatar. I want my regular expression return true if it contains at least one UpperCase in String.

    • npinti
      npinti about 9 years
      I think that the evaluateWithObject tries to match the entire string. Try using something like so: ^.*?[A-Z].*?$.
    • Anish Parajuli 웃
      Anish Parajuli 웃 about 9 years
      i didnot get that..Can you elaborate it more about that regular expression??
    • npinti
      npinti about 9 years
      It might be that the evaluateWithObject function call is trying to match the entire string, thus, given a string like this: Hello123, and a regular expression like so: [A-Z]+, Swift is mapping it to something like so: ^[A-Z]+$. This means that it will expect that the entire provided string matches exactly. Please try to make the change, if it works I'll post an answer with some more information. I am not a Swift developer, so I might be wrong, which is why I posted this as a comment.
    • Anish Parajuli 웃
      Anish Parajuli 웃 about 9 years
      thanks for your explanation.But its not working :(
    • npinti
      npinti about 9 years
      Is it still failing on the same item or is the method as a whole failing? As is, your method should still return false negatives.
    • Rory McKinnel
      Rory McKinnel about 9 years
      Why not just compare the lower case version of the string with the original and if it is not the same, then it has one or more upper case letters. Much simpler and less complicated.
    • Anish Parajuli 웃
      Anish Parajuli 웃 about 9 years
      @npinti the regular expression is not matching..and returning false...@rory i think thats not my case
    • Rory McKinnel
      Rory McKinnel about 9 years
      This looks an ideal solution to me: stackoverflow.com/questions/12984912/…
  • Joshua Arvin Lat
    Joshua Arvin Lat about 9 years
    Note: simple replace || with && if you need all rules to apply
  • Anish Parajuli 웃
    Anish Parajuli 웃 about 9 years
    you know that doesnot work....all three result is getting true...although i insert only numerics...because .* matches all the strings..
  • Joshua Arvin Lat
    Joshua Arvin Lat about 9 years
    there are some typos in the original code such as texttest.evaluateWithObject("AniP") and should be replaced by texttest.evaluateWithObject(text) for it to evaluate the parameter. texttest2 is also using the number RegEx (it should use the special character RegEx) :)
  • Joshua Arvin Lat
    Joshua Arvin Lat about 9 years
    That's the reason why all three results are evaluating to true since the first expression will always evaluate to true and the second and third expressions are doing the same thing
  • Joshua Arvin Lat
    Joshua Arvin Lat about 9 years
    @anishparajuli no problem!
  • Tung Fam
    Tung Fam almost 7 years
    added some more special chars: ".*[\".,!&~``^%$#_<>@(+)/-]+.*"
  • pierre23
    pierre23 about 6 years
    Much better... Thank you
  • Nick N
    Nick N over 4 years
    This regex worked better for me with Swift 5. The one from @Patrick R didn't seem to work. Ah the elusive cryptic nature of regex confuses again..
  • Antonio Labra
    Antonio Labra almost 4 years
    G R E A T J O B <3
  • Ahmed Abdallah
    Ahmed Abdallah over 3 years
    You are the GOAT