我正在尝试使用regexp编写密码验证功能,并且不知道如何操作。 Golang正则表达式与其他语言不同。有人知道,这个正则表达式应该是什么样的? 该模式应验证:
/*
* Password rules:
* at least 7 letters
* at least 1 number
* at least 1 upper case
* at least 1 special character
*/
答案 0 :(得分:14)
这实际上是不可能的,因为Go的regex不支持回溯。
然而,它很容易实现,一个简单的例子:
func verifyPassword(s string) (sevenOrMore, number, upper, special bool) {
letters := 0
for _, c := range s {
switch {
case unicode.IsNumber(c):
number = true
case unicode.IsUpper(c):
upper = true
letters++
case unicode.IsPunct(c) || unicode.IsSymbol(c):
special = true
case unicode.IsLetter(c) || c == ' ':
letters++
default:
//return false, false, false, false
}
}
sevenOrMore = letters >= 7
return
}
答案 1 :(得分:7)
正确的正则表达式是......这里没有正则表达式。
您可以定义一个验证密码的自定义函数,并将其与其他框架结合使用,以帮助验证字段,例如mccoyst/validate(在此discussion about parameter validation中提到)
您还有go-validator/validator允许定义类似的验证(但我仍然会使用自定义验证器而不是一个或多个正则表达式。)
注意:go regexp基于 re2 ,这是一个高效的,有原则的正则表达式库)。
所以主要的权衡是没有反向引用,例如:
(abc)\1
和没有匹配的后台。
作为交换,你得到高速正则表达式。
答案 2 :(得分:1)
基于@OneOfOne's的答案,并改进了一些错误消息
package main
import (
"fmt"
"strings"
"unicode"
)
func verifyPassword(password string) error {
var uppercasePresent bool
var lowercasePresent bool
var numberPresent bool
var specialCharPresent bool
const minPassLength = 8
const maxPassLength = 64
var passLen int
var errorString string
for _, ch := range password {
switch {
case unicode.IsNumber(ch):
numberPresent = true
passLen++
case unicode.IsUpper(ch):
uppercasePresent = true
passLen++
case unicode.IsLower(ch):
lowercasePresent = true
passLen++
case unicode.IsPunct(ch) || unicode.IsSymbol(ch):
specialCharPresent = true
passLen++
case ch == ' ':
passLen++
}
}
appendError := func(err string) {
if len(strings.TrimSpace(errorString)) != 0 {
errorString += ", " + err
} else {
errorString = err
}
}
if !lowercasePresent {
appendError("lowercase letter missing")
}
if !uppercasePresent {
appendError("uppercase letter missing")
}
if !numberPresent {
appendError("atleast one numeric character required")
}
if !specialCharPresent {
appendError("special character missing")
}
if !(minPassLength <= passLen && passLen <= maxPassLength) {
appendError(fmt.Sprintf("password length must be between %d to %d characters long", minPassLength, maxPassLength))
}
if len(errorString) != 0 {
return fmt.Errorf(errorString)
}
return nil
}
// Let's test it
func main() {
password := "Apple"
err := verifyPassword(password)
fmt.Println(password, " ", err)
}
答案 3 :(得分:0)
从邻近的答案开始,我也写了一个对我来说很好用的辅助函数。这只是假设总体密码长度令人满意。查看以下内容...
func isValid(s string) bool {
var (
hasMinLen = false
hasUpper = false
hasLower = false
hasNumber = false
hasSpecial = false
)
if len(s) >= 7 {
hasMinLen = true
}
for _, char := range s {
switch {
case unicode.IsUpper(char):
hasUpper = true
case unicode.IsLower(char):
hasLower = true
case unicode.IsNumber(char):
hasNumber = true
case unicode.IsPunct(char) || unicode.IsSymbol(char):
hasSpecial = true
}
}
return hasMinLen && hasUpper && hasLower && hasNumber && hasSpecial
}
isValid("pass") // false
isValid("password") // false
isValid("Password") // false
isValid("P@ssword") // false
isValid("P@ssw0rd") // true
答案 4 :(得分:0)
下面是我使用自定义消息实现上述答案,并以某种方式以一种好的方式扭曲它们(性能感知代码)。
package main
import (
"fmt"
"strconv"
"unicode"
)
func main() {
pass := "12345678_Windrol"
// call the password validator and give it field name to be known by the user, password, and the min and max password length
isValid, errs := isValidPassword("Password", pass, 8, 32)
if isValid {
fmt.Println("The password is valid")
} else {
for _, v := range errs {
fmt.Println(v)
}
}
}
func isValidPassword(field, s string, min, max int) (isValid bool, errs []string) {
var (
isMin bool
special bool
number bool
upper bool
lower bool
)
//test for the muximum and minimum characters required for the password string
if len(s) < min || len(s) > max {
isMin = false
appendError("length should be " + strconv.Itoa(min) + " to " + strconv.Itoa(max))
}
for _, c := range s {
// Optimize perf if all become true before reaching the end
if special && number && upper && lower && isMin {
break
}
// else go on switching
switch {
case unicode.IsUpper(c):
upper = true
case unicode.IsLower(c):
lower = true
case unicode.IsNumber(c):
number = true
case unicode.IsPunct(c) || unicode.IsSymbol(c):
special = true
}
}
// append error
appendError := func(err string) {
errs = append(errs, field+" "+err)
}
// Add custom error messages
if !special {
appendError("should contain at least a single special character")
}
if !number {
appendError("should contain at least a single digit")
}
if !lower {
appendError("should contain at least a single lowercase letter")
}
if !upper {
appendError("should contain at least single uppercase letter")
}
// if there is any error
if len(errs) > 0 {
return false, errs
}
// everyting is right
return true, errs
}