为了账号安全,请及时绑定邮箱和手机立即绑定

不支持的 Perl 语法:“(?<”

不支持的 Perl 语法:“(?<”

Go
万千封印 2022-09-19 14:45:01
我想解析cmd “gpg --列表键”的结果,以在浏览器上显示它。厘米输出如下:    pub   rsa3072 2021-08-03 [SC] [expires: 2023-08-03]          07C47E284765D5593171C18F00B11D51A071CB55    uid           [ultimate] user1 <user1@example.com>    sub   rsa3072 2021-08-03 [E] [expires: 2023-08-03]        pub   rsa3072 2021-08-04 [SC]          37709ABD4D96324AB8CBFC3B441812AFBCE7A013    uid           [ultimate] user2 <user2@example.com>    sub   rsa3072 2021-08-04 [E]我期望这样的事情:    {        {uid : user1@example.com},        {uid : user2@example.com},    }代码如下:    type GPGList struct{        uid string    }        //find list keys    func Findlistkeys(){        pathexec, _ := exec.LookPath("gpg")        cmd := exec.Command(pathexec, "--list-keys")        cmdOutput := &bytes.Buffer{}        cmd.Stdout = cmdOutput        printCommand(cmd)        err := cmd.Run()        printError(err)        output := cmdOutput.Bytes()        printOutput(output)        GPG := GPGList{}        parseOutput(output, &GPG)        fmt.Println(GPG)    }        func printCommand(cmd *exec.Cmd) {        fmt.Printf("==> Executing: %s\n", strings.Join(cmd.Args, " "))    }        func printError(err error) {        if err != nil {                os.Stderr.WriteString(fmt.Sprintf("==> Error: %s\n", err.Error()))        }    }        func printOutput(outs []byte) {        if len(outs) > 0 {                fmt.Printf("==> Output: %s\n", string(outs))        }    }        func parseOutput(outs []byte, GPG *GPGList) {        var uid = regexp.MustCompile(`(?<=\<)(.*?)(?=\>)`)        fmt.Println(uid)    }它以以下消息结尾:    panic: regexp: Compile(`(?<=\<)(.*?)(?=\>)`): error parsing regexp: invalid or unsupported Perl syntax: `(?<到目前为止,我正在与正则表达式堆叠。它不明白为什么它不想编译...这是怎么回事?我已经在在线模拟器上测试了正则表达式,它看起来还不错,但是它有问题。有什么建议吗?
查看完整描述

3 回答

?
慕的地8271018

TA贡献1796条经验 获得超4个赞

这是另一个基于机器可读输出的解决方案。gpg --list-keys --with-colons


它仍然是一个缓慢的解决方案,但易于编写,易于更新,不使用正则表达式。


一个聪明的人可以带来一个更快的解决方案,而不会增加一个疯狂的复杂性墙。(只需循环遍历字符串,直到捕获字符串,直到<>)


这是基于一个简单的csv阅读器,因此您可以将其插入到命令的输出流中。执行实例,或其他任何内容。


最大的优点是它不需要缓冲内存中的整个数据,它可以流解码。


package main


import (

    "encoding/csv"

    "fmt"

    "io"

    "regexp"

    "strings"

)


func main() {

    fmt.Printf("%#v\n", extractEmailsCSV(csvInput))

}


var uid = regexp.MustCompile(`\<(.*?)\>`)


func extractEmailsRegexp(input string) (out []string) {

    submatchall := uid.FindAllString(input, -1)

    for _, element := range submatchall {

        element = strings.Trim(element, "<")

        element = strings.Trim(element, ">")

        out = append(out, element)

    }

    return

}


func extractEmailsCSV(input string) (out []string) {

    r := strings.NewReader(input)

    csv := csv.NewReader(r)

    csv.Comma = ':'

    csv.ReuseRecord = true

    csv.FieldsPerRecord = -1


    for {

        records, err := csv.Read()

        if err == io.EOF {

            break

        } else if err != nil {

            panic(err)

        }


        if len(records) < 10 {

            continue

        }


        r := records[9]

        if strings.Contains(r, "@") {

            begin := strings.Index(r, "<")

            end := strings.Index(r, ">")

            if begin+end > 0 {

                out = append(out, r[begin+1:end])

            }

        }

    }

    return

}


var regexpInput = `

    pub   rsa3072 2021-08-03 [SC] [expires: 2023-08-03]

          07C47E284765D5593171C18F00B11D51A071CB55

    uid           [ultimate] user1 <user1@example.com>

    sub   rsa3072 2021-08-03 [E] [expires: 2023-08-03]


    pub   rsa3072 2021-08-04 [SC]

          37709ABD4D96324AB8CBFC3B441812AFBCE7A013

    uid           [ultimate] user2 <user2@example.com>

    sub   rsa3072 2021-08-04 [E]

`


var csvInput = `pub:u:1024:17:51FF9A17136C5B87:1999-04-24::59:-:Tony Nelson <tnelson@techie.com>:

uid:u::::::::Tony Nelson <tnelson@conceptech.com>:

`

我们没有完全相同的基准测试设置,但无论如何。如果您认为它膨胀了比较,请随时提供更好的工作台设置。


这是基准测试设置


package main


import (

    "strings"

    "testing"

)


func BenchmarkCSV_1(b *testing.B) {

    input := strings.Repeat(csvInput, 1)

    b.ResetTimer()

    for i := 0; i < b.N; i++ {

        _ = extractEmailsCSV(input)

    }

}

func BenchmarkRegExp_1(b *testing.B) {

    input := strings.Repeat(regexpInput, 1)

    b.ResetTimer()

    for i := 0; i < b.N; i++ {

        _ = extractEmailsRegexp(input)

    }

}


func BenchmarkCSV_10(b *testing.B) {

    input := strings.Repeat(csvInput, 10)

    b.ResetTimer()

    for i := 0; i < b.N; i++ {

        _ = extractEmailsCSV(input)

    }

}

func BenchmarkRegExp_10(b *testing.B) {

    input := strings.Repeat(regexpInput, 10)

    b.ResetTimer()

    for i := 0; i < b.N; i++ {

        _ = extractEmailsRegexp(input)

    }

}


func BenchmarkCSV_100(b *testing.B) {

    input := strings.Repeat(csvInput, 100)

    b.ResetTimer()

    for i := 0; i < b.N; i++ {

        _ = extractEmailsCSV(input)

    }

}

func BenchmarkRegExp_100(b *testing.B) {

    input := strings.Repeat(regexpInput, 100)

    b.ResetTimer()

    for i := 0; i < b.N; i++ {

        _ = extractEmailsRegexp(input)

    }

}

这是结果


BenchmarkCSV_1

BenchmarkCSV_1-4              242736          4200 ns/op        5072 B/op         18 allocs/op

BenchmarkRegExp_1

BenchmarkRegExp_1-4           252232          4466 ns/op         400 B/op          9 allocs/op

BenchmarkCSV_10

BenchmarkCSV_10-4              68257         17335 ns/op        7184 B/op         40 allocs/op

BenchmarkRegExp_10

BenchmarkRegExp_10-4           29871         39947 ns/op        3414 B/op         68 allocs/op

BenchmarkCSV_100

BenchmarkCSV_100-4              7538        141609 ns/op       25872 B/op        223 allocs/op

BenchmarkRegExp_100

BenchmarkRegExp_100-4           1726        674718 ns/op       37858 B/op        615 allocs/op

在原始速度和分配方面,正则表达式在小数据集上更好,尽管只要有一点点数据,正则表达式就会变慢并且分配更多因素。


另见 https://pkg.go.dev/testing


我的结论是,不要使用正则表达式...此外,优化正则表达式即使不是不可能,也是困难的,因为优化算法以解析某些文本输入是可行的,如果不是那么容易。


总而言之,如果没有一个深思熟虑的程序员来驱动它,即使是最快和最好的运行时也算不了什么。


查看完整回答
反对 回复 2022-09-19
?
哔哔one

TA贡献1854条经验 获得超8个赞

所以我更新了正则表达式...但是由于正在研究在线模拟器,我真的很惊讶。为什么正则表达式不能在所有语言中都一样工作...(?<=\<)(.*?)(?=\>)


    func parseOutput(outs []byte, GPG *GPGList) {

        var uid = regexp.MustCompile(`\<(.*?)\>`)

        submatchall := uid.FindAllString(string(outs), -1)

        for _, element := range submatchall {

            element = strings.Trim(element, "<")

            element = strings.Trim(element, ">")

            fmt.Println(element)

        }

    }


查看完整回答
反对 回复 2022-09-19
?
qq_花开花谢_0

TA贡献1835条经验 获得超7个赞

正则表达式包使用 RE2 接受的语法。从 https://github.com/google/re2/wiki/Syntax

(?<=re) 后的文本匹配 re (不支持)

因此,错误消息:

解析正则表达式时出错: 无效或不受支持的 Perl 语法:(?<

在线模拟器可能正在测试不同的正则表达式语法。您将需要找到替代的正则表达式编码或不同的正则表达式包。

您可以尝试的替代编码是(游乐场)。这很简单,可能与您的原始意图不符。\<([^\>]*)\>


查看完整回答
反对 回复 2022-09-19
  • 3 回答
  • 0 关注
  • 106 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信