2015-12-06 3 views
7

Я ищу пакет, который будет принимать строку, такую ​​как -v --format "some example" -i test и разобрать его в срезе строк, обработки кавычки, пробелы и т.д. правильно:Разбор строки в командную строку флаги и аргументы в Golang

-v 
--format 
some example 
-i 
test 

Я проверил встроенный пакет flag, а также другие пакеты обработки флагов в Github, но ни один из них, похоже, не справляется с этим конкретным случаем анализа синтаксической строки в токенах. Прежде чем пытаться это сделать, я предпочел бы найти пакет, так как я уверен, что есть много особых случаев для обработки.

Любое предложение?

+0

Это смесь того, что делает оболочки (в кавычках строки группировка) и конкретное поведение гну инструментов вариант синтаксического анализа (Вкрапленная арг и флаги, и разные длинные/короткий формат флага). Я не знаю, кто их объединяет в пакет. – JimB

+0

Быстрый хак (если вы гибки, чтобы изменить способ обеспечить ввод) будет (см 'документации flag' пакета): \t \t множества: = & flag.FlagSet {} \t \t v: = множество .Bool ("v", false, "") \t Формат: = set.String ("format", "", "") \t i: = set.String ("i", "", "") \t \t set.Parse ([] строка { '-V',' --format = "некоторые примеры", '-i = test'}) \t для K, V: = диапазон set.Args() { \t \t log.Println (к, v) \t} \t \t log.Printf ("v =% v = формат% Vi =% v", * v * формат, * я) –

+0

Я не уверен, если Я понимаю. Вы планируете сделать что-то вроде: 'cmd -v --format 'в качестве примера« -i test »? Если это так, вы можете просто взять все аргументы из 'os.Args'. – 425nesp

ответ

1

Для информации, это функция, которую я создал.

Он разделяет команду на свои аргументы. Например, cat -v "some file.txt", вернет ["cat", "-v", "some file.txt"].

Он также правильно обрабатывает экранированные символы, в частности пробелы. Так cat -v some\ file.txt также правильно разбить на ["cat", "-v", "some file.txt"]

func parseCommandLine(command string) ([]string, error) { 
    var args []string 
    state := "start" 
    current := "" 
    quote := "\"" 
    escapeNext := true 
    for i := 0; i < len(command); i++ { 
     c := command[i] 

     if state == "quotes" { 
      if string(c) != quote { 
       current += string(c) 
      } else { 
       args = append(args, current) 
       current = "" 
       state = "start" 
      } 
      continue 
     } 

     if (escapeNext) { 
      current += string(c) 
      escapeNext = false 
      continue 
     } 

     if (c == '\\') { 
      escapeNext = true 
      continue 
     } 

     if c == '"' || c == '\'' { 
      state = "quotes" 
      quote = string(c) 
      continue 
     } 

     if state == "arg" { 
      if c == ' ' || c == '\t' { 
       args = append(args, current) 
       current = "" 
       state = "start" 
      } else { 
       current += string(c) 
      } 
      continue 
     } 

     if c != ' ' && c != '\t' { 
      state = "arg" 
      current += string(c) 
     } 
    } 

    if state == "quotes" { 
     return []string{}, errors.New(fmt.Sprintf("Unclosed quote in command line: %s", command)) 
    } 

    if current != "" { 
     args = append(args, current) 
    } 

    return args, nil 
}