After reading this post, I know I need to use a backquotes ( ` ) to wrap my regex pattern. Now I have regex pattern /^(?=^.{8,}$)(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?!.*\s)[0-9a-zA-Z!@#$%^&*()]*$/
to check password pattern whether is correct. I have tested it with PHP and it work correctly. But it does not work in Go. Why?
By the way, what is the type of backquoted ( ` ) variable? it seems not string
type. How can I declare this variable container?
Testing Code
package main
import(
"fmt"
"regexp"
)
func main(){
re := regexp.MustCompile(`/^(?=^.{8,}$)(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?!.*\s)[0-9a-zA-Z!@#$%^&*()]*$/`)
fmt.Println(re.MatchString("aSfd46Fgwaq"))
}
Testing Result
Running...
panic: regexp: Compile(`/^(?=^.{8,}$)(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?!.*\s)[0-9a-zA-Z!@#$%^&*()]*$/`): error parsing regexp: invalid or unsupported Perl syntax: `(?=`
goroutine 1 [running]:
panic(0x4efae0, 0xc82000a340)
/usr/local/go/src/runtime/panic.go:481 +0x3e6
regexp.MustCompile(0x576140, 0x4b, 0x100000000)
/usr/local/go/src/regexp/regexp.go:232 +0x16f
main.main()
/home/casper/.local/share/data/liteide/goplay.go:9 +0x30
exit status 2
Error: process exited with code 1.
Thank you!
Go regexp does not support lookarounds. Also, the /.../
regex delimiters are not supported, either (there are special methods in Go to express those).
You may either use a lookaround-supporting regex library for Go (here is a PCRE-supporting one) or split the conditions and use several small, readable regexps:
package main
import (
"fmt"
"regexp"
"unicode/utf8"
)
func main() {
s := "aSfd46Fgwaq"
lower_cond := regexp.MustCompile(`[a-z]`)
upper_cond := regexp.MustCompile(`[A-Z]`)
digit_cond := regexp.MustCompile(`[0-9]`)
whole_cond := regexp.MustCompile(`^[0-9a-zA-Z!@#$%^&*()]*$`)
pass_len := utf8.RuneCountInString(s)
fmt.Println(lower_cond.MatchString(s) && upper_cond.MatchString(s) && digit_cond.MatchString(s) && whole_cond.MatchString(s) && pass_len >= 8)
}
NOTE: I used utf8.RuneCountInString
in the demo to make sure even UTF8 string length is parsed correctly. Otherwise, you might use len(s)
that will count bytes that should suffice for ASCII input.
Update
If the performance is not satisfactory, you may consider using a simpler non-regex approach:
package main
import "fmt"
func main() {
myString := "aSfd46Fgwaq"
has_digit := false
has_upper := false
has_lower := false
pass_length := len(myString)
for _, value := range myString {
switch {
case value >= '0' && value <= '9':
has_digit = true
case value >= 'A' && value <= 'Z':
has_upper = true
case value >= 'a' && value <= 'z':
has_lower = true
}
}
fmt.Println(has_digit && has_upper && has_lower && pass_length >= 8)
}
See another Go demo