命令行解析算法
能够对复杂的引号嵌套、空格进行解析。
如:cmd -a " a b \" ' ' \" c " -b abc => cmd -a a b " ' ' " c -b abc
func CmdToArgs(cmd string) []string {
var args []string
var closedChar byte // 闭合字符 ' or "
var needClose bool // 当前是否需要闭合
var toCompleteArg string // 要拼接的完成的参数,就是 ' 或 " 包围的参数值
addToArgs := func() {
toCompleteArg = strings.ReplaceAll(toCompleteArg, `\'`, `'`)
toCompleteArg = strings.ReplaceAll(toCompleteArg, `\"`, `"`)
args = append(args, toCompleteArg)
toCompleteArg = ""
}
for i := 0; i < len(cmd); i++ {
if (cmd[i] == '\'' || cmd[i] == '"') && cmd[i-1] != '\\' { // 不用判断 i > 0
if !needClose {
needClose = true
closedChar = cmd[i]
continue
} else if cmd[i] == closedChar {
needClose = false
addToArgs()
continue
}
}
if cmd[i] == ' ' && needClose { // 空格作为参数值的一部分
toCompleteArg += " "
} else if cmd[i] == ' ' && toCompleteArg != "" { // 非引号闭合的参数结束
addToArgs()
} else if cmd[i] != ' ' {
toCompleteArg += string(cmd[i])
if i == len(cmd)-1 {
addToArgs()
}
}
}
return args
}
测试用例:
func TestCmdToArgs(t *testing.T) {
testCases := []struct {
input string
want []string
}{
{`cmd -i "1 ' \" 2"`, []string{`cmd`, `-i`, `1 ' " 2`}},
{` cmd -id 123 -name '' -e " \'\'\" "`, []string{`cmd`, `-id`, `123`, `-name`, ``, `-e`, ` ''" `}},
{`cmd -a ' " " ' -b " ''aa" -c cc`, []string{`cmd`, `-a`, ` " " `, `-b`, ` ''aa`, `-c`, `cc`}},
}
sliceToStr := func(s []string) (str string) {
for _, i := range s {
str += i
}
return str
}
for _, testCase := range testCases {
if sliceToStr(cmdToArgs(testCase.input)) != sliceToStr(testCase.want) {
t.Errorf("input:%s want:%s", testCase.input, testCase.want)
}
}
}