在iOS Swift中使用正则表达式验证密码

3

我需要验证用户密码是否符合以下要求:

  • 8个或更多字符。

  • 包含1个字符和1个数字

  • 可以输入字母、数字和符号

有人知道如何使用正则表达式来实现这个吗?

我已经尝试过自己解决这个问题,但迄今为止没有任何效果。下面是我最新尝试的代码。

func isPasswordHasEightCharacter(password: String) -> Bool {
    let passWordRegEx = "^.{8,}$"
    let passwordTest = NSPredicate(format: "SELF MATCHES %@", passWordRegEx)
    return passwordTest.evaluate(with: password)
}

func isPasswordHasNumberAndCharacter(password: String) -> Bool {
    let passRegEx = "^(?=.*[a-z])(?=.*[0-9])"
    let passwordTest = NSPredicate(format: "SELF MATCHES %@", passRegEx)
    return passwordTest.evaluate(with: password)
}

func isPasswordHasNumberAndCharacterSign(password: String) -> Bool {
    let passWordRegEx = "^(?!.[^a-zA-Z0-9@#${'$'}^+=])"
    let passwordTest = NSPredicate(format: "SELF MATCHES %@", passWordRegEx)
    return passwordTest.evaluate(with: password)
}

你调试过你的函数了吗?具体发生了什么?有没有抛出任何错误? - undefined
你所说的“字母、数字和符号”,是指“任何非空白字符”吗? - undefined
请检查以下链接的stackoverflow页面:https://dev59.com/k1kS5IYBdhLWcg3w6qXU - undefined
@WiktorStribiżew 是的 - undefined
好的,请看下面的答案。 - undefined
@TiagoSilva 当我检查密码:Pa$$w0rd时,每个函数只有第一个函数返回true。 - undefined
2个回答

2
主要问题是使用NSPredicateMATCHES时需要完全匹配并消耗整个输入字符串。而前后环视(lookarounds)不会消耗文本,也就是说,它们匹配的文本不会被添加到匹配值中,正则表达式索引仍然停留在尝试匹配前后环视模式之前的位置。
因此,可以通过以下方式修复最后两部分:
func isPasswordHasNumberAndCharacter(password: String) -> Bool {
    let passRegEx = "(?=[^a-z]*[a-z])[^0-9]*[0-9].*"
    let passwordTest = NSPredicate(format: "SELF MATCHES %@", passRegEx)
    return passwordTest.evaluate(with: password)
}

func isPasswordHasNumberAndCharacterSign(password: String) -> Bool {
    let passWordRegEx = "[a-zA-Z0-9!@#$%^&*]+"
    let passwordTest = NSPredicate(format: "SELF MATCHES %@", passWordRegEx)
    return passwordTest.evaluate(with: password)
}

第一部分没问题,虽然你不需要使用^$锚点(因为整个字符串输入必须匹配模式)。然而,要检查字符串的长度,你甚至不需要正则表达式:参见Get the length of a String

注意:

  • ^(?=[^a-z]*[a-z])[^0-9]*[0-9].*\z匹配包含至少一个小写ASCII字母和至少一个ASCII数字的字符串
  • ^[a-zA-Z0-9!@#$%^&*]+$将匹配只包含ASCII字母、数字和一些特定符号的字符串。如果你包含一个-,确保它在末尾。如果需要添加[],也要转义它们。

如果你想将所有内容合并成一个正则表达式,可以使用以下表达式:

let passRegEx = "(?=[^a-z]*[a-z])(?=[^0-9]*[0-9])[a-zA-Z0-9!@#$%^&*]{8,}"

或者,如果您没有使用正则表达式与NSPredicate MATCHES一起使用锚点:
let passRegEx = "\\A(?=[^a-z]*[a-z])(?=[^0-9]*[0-9])[a-zA-Z0-9!@#$%^&*]{8,}\\z"

我只想要最后一个函数包含字母、数字和符号,比如(!@#$%^&*)。当我输入特殊字符,比如“|;,”或者片假名日语时,返回false。 - undefined
@HiệpChelsea 所以,你的意思是只匹配ASCII字母、数字和一些特定符号吗?我已经更新了答案,请检查。 - undefined
是的,当我输入一些字符时,我想显示消息:“已输入无效值”。 - undefined
@HiệpChelsea,那就展示一下吧。上面的函数应该可以正常工作了。现在你知道为什么你的正则表达式失败了。剩下的就取决于你自己,与当前的问题无关。 - undefined
@HiệpChelsea (?=\\S*)(?=\\s*)是没有意义的,因为你需要一个空字符串存在-它总是存在的。你能提供一些你想要通过和失败的示例字符串吗?请在https://regex101.com/r/g2OI5K/1上更新这些示例。 - undefined
显示剩余2条评论

1
在这个解决方案中,每个要求都被单独检查,以避免复杂的正则表达式。此解决方案支持像ôöệż等字符的变体。
func validatePassword(_ password: String) -> Bool {
    //At least 8 characters
    if password.count < 8 {
        return false
    }

    //At least one digit
    if password.range(of: #"\d+"#, options: .regularExpression) == nil {
        return false
    }

    //At least one letter
    if password.range(of: #"\p{Alphabetic}+"#, options: .regularExpression) == nil {
        return false
    }

    //No whitespace charcters
    if password.range(of: #"\s+"#, options: .regularExpression) != nil {
        return false
    }

    return true
}

一些测试用例。
print(validatePassword("abc"))        // --> false
print(validatePassword("abcdefgh"))   // --> false
print(validatePassword("abcde fgh1")) // --> false
print(validatePassword("abcdefgh1"))  // --> true
print(validatePassword("abcåäö123"))  // --> true
print(validatePassword("ABC123€%&"))  // --> true
print(validatePassword("@èệżôøö123")) // --> true

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接