使用Go解析字符串参数类似于命令行参数

3

如何将一个字符串解析成命令行参数的形式?我希望能够使用flag和/或pflag对该字符串进行解析。请问应该如何操作?

package main

import (
    "fmt"
    "os"

    flag "github.com/spf13/pflag"
)

func main() {
    command := `unimportant -fb "quoted string"`
    var (
        foo bool
        bar string
    )
    flag.BoolVarP(&foo, "foo", "f", false, "foo")
    flag.StringVarP(&bar, "bar", "b", "default", "bar")

    // Parse command
    os.Args = append(os.Args, "-fb", "quoted string")
    flag.Parse()

    fmt.Println(command)
    fmt.Println("foo", foo)
    fmt.Println("bar", bar)
}
2个回答

4
最简单的方法是使用包shellwords将您的字符串解析为一个shell单词的 argv,然后使用除flagpflag之外的命令行解析器来支持解析任意的argv(例如flags,但有很多可供选择)。
// Parse  your string into an []string as the shell would.

argv, err := shellwords.Parse("./foo --bar=baz")
// argv should be ["./foo", "--bar=baz"]

...

// define your options, etc. here

...

extraArgs, err := flags.ParseArgs(&opts, argv)

1
flagpflag都可以解析任意的argv,请参考flag.FlagSet.Parsepflag.FlagSet.Parse - erdnaxeli
@erdnaxeli — 原始问题是希望将任意字符串(就像在命令行上输入的那样)解析为shell所做的"单词",并生成一个argv。例如,字符串foo bar"baz" -o some \file.name".txt"将被解析为单词foobarbaz-osome file.name.txt。然后,您需要决定是否要展开通配符(您可能需要)。 - Nicholas Carey
是的,你说得对,我的评论离题了。 - erdnaxeli

1

正则表达式可以用来检测每个参数。一个参数有两种可能的形式:

  1. 一组字母和负号:[-a-zA-Z]+
  2. 两个引号之间夹着的东西:".*?"

关于 regexp 包的信息: https://pkg.go.dev/regexp

关于 regexp 语法的信息: https://pkg.go.dev/regexp/syntax@go1.17.6

re := regexp.MustCompile(`([-a-zA-Z]+)|(".*?[^\\]")|("")`)
command := `unimportant -fb "quoted string"`

allArgs := re.FindAllString(command, -1)

//fmt.Printf("%+v\n", allArgs)

// to remove "
for _, arg := range allArgs {
    if arg[0] == '"' {
        arg = arg[1 : len(arg)-1]
    }
    fmt.Println(arg)
}

输出:

unimportant
-fb
quoted string

转换成中文的内容:unimportant -fb "quoted string \"with\" escaped quotes" 中的转义引号怎么处理? - pythonian 23
正则表达式已更改为: ([-a-zA-Z]+)|(".*?[^\\]")|("") - Amirreza Noori

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