用于密码检查的PHP正则表达式模式在Go中不起作用

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)
}

See Go playground demo

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