Каков шаблон проектирования для обработки аргументов командной строки?

StackOverflow https://stackoverflow.com/questions/54421

Вопрос

Если вы пишете программу, исполняемую из командной строки, вам часто нужно предложить пользователю несколько опций или флагов, а также, возможно, более одного аргумента.Я много раз сталкивался с этим, но существует ли какой-то шаблон проектирования для циклического перебора аргументов и вызова соответствующих функций-обработчиков?

Учитывать:

myprogram -f filename -d directory -r regex

Как вы организуете функции-обработчики после получения аргументов, используя любые встроенные функции вашего языка?(приветствуются ответы на конкретном языке, если это поможет вам сформулировать ответ)

Это было полезно?

Решение

Я не знаю ни одного задокументированного «шаблона» обработки.

Я считаю, что одной из старейших библиотек/API для обработки аргументов является getopt.Поиск в Google "getopt" показывает множество страниц руководства и ссылок на реализации.

Обычно в моем приложении есть служба предпочтений или настроек, с которой процессор аргументов знает, как взаимодействовать.Затем аргументы преобразуются во что-то в этой службе, что приложение затем запрашивает.Это может быть просто словарь настроек (например, строковый параметр с именем «имя файла»).

Другие советы

Я думаю, что следующий ответ больше соответствует тому, что вы ищете:

Вам следует рассмотреть возможность применения шаблона шаблона (метод шаблона в разделе «Шаблоны проектирования» [Gamma, el al]).

Вкратце, общая обработка выглядит так:

If the arguments to the program are valid then
    Do necessary pre-processing
    For every line in the input
        Do necessary input processing
    Do necessary post-processing
Otherwise
    Show the user a friendly usage message

Короче говоря, реализуйте класс ConsoleEngineBase, который имеет методы для:

PreProcess()
ProcessLine()
PostProcess()
Usage()
Main()

Затем создайте шасси, которое создает экземпляр экземпляра ConsoleEngine() и отправляет сообщение Main() для его запуска.

Чтобы увидеть хороший пример того, как применить это к программе консоли или командной строки, перейдите по следующей ссылке:http://msdn.microsoft.com/en-us/magazine/cc164014.aspx

Пример написан на C#, но идеи легко реализовать в любой другой среде.

Вы могли бы рассматривать GetOpt() как часть обработки аргументов (предварительная обработка).

Надеюсь это поможет.

Вы не упомянули язык, но Java нам очень понравился. Интерфейс командной строки Apache Commons.Для C/C++ используйте getopt.

Несколько комментариев по этому поводу...

Во-первых, хотя шаблонов как таковых не существует, написание парсера — это, по сути, механическое упражнение, поскольку, имея грамматику, можно легко сгенерировать парсер.На ум приходят такие инструменты, как Bison и ANTLR.

Тем не менее, генераторы парсеров обычно излишни для командной строки.Таким образом, обычная схема — написать его самостоятельно (как продемонстрировали другие) несколько раз, пока вам не надоест возиться с утомительными деталями и вы не найдете библиотеку, которая сделает это за вас.

Я написал один для C++, который экономит кучу усилий, которые прилагает getopt, и позволяет удобно использовать шаблоны: TCLAP

Ну, это старый пост, но я все равно хотел бы внести свой вклад.Вопрос был посвящен выбору шаблонов проектирования, однако я видел много дискуссий о том, какую библиотеку использовать.Я проверил ссылку Microsoft на Линдси, в которой рассказывается об использовании шаблона дизайна шаблона.

Однако меня не убедил этот пост.Целью шаблона шаблона является определение шаблона, который будет реализован различными другими классами для обеспечения единообразного поведения.Я не думаю, что синтаксический анализ командной строки сюда подходит.

Я бы предпочел использовать шаблон проектирования «Команда».Этот шаблон лучше всего подходит для опций, управляемых через меню.

http://www.blackwasp.co.uk/Command.aspx

поэтому в вашем случае -f, -d и -r все становятся командами, для которых определен общий или отдельный получатель.Таким образом, в будущем можно будет определить больше получателей.Следующим шагом будет объединение этих обязанностей команд, если потребуется цепочка обработки.Для чего я бы выбрал.

http://www.blackwasp.co.uk/ChainOfResponsibility.aspx

Я думаю, что комбинация этих двух вариантов лучше всего подходит для организации кода для обработки командной строки или любого подхода, управляемого меню.

А повышение::program_options Библиотека хороша, если вы работаете на C++ и можете позволить себе роскошь использовать Boost.

Предполагая, что у вас есть объект «config», который вы хотите настроить с помощью флагов, и подходящий анализатор командной строки, который занимается анализом командной строки и предоставляет постоянный поток параметров, вот блок псевдокода.

while (current_argument = cli_parser_next()) {
    switch(current_argument) {
        case "f": //Parser strips the dashes
        case "force":
            config->force = true;
            break;
        case "d":
        case "delete":
            config->delete = true;
            break;
        //So on and so forth
        default:
            printUsage();
            exit;
    }
}

Я предпочитаю такие параметры, как «-t текст» и «-i 44»;Мне не нравится «-fname» или «--very-long-argument=some_value».

И «-?», «-h» и «/h» создают экран справки.

Вот как выглядит мой код:

int main (int argc, char *argv[])
   {  int i;
      char *Arg;
      int ParamX, ParamY;
      char *Text, *Primary;

   // Initialize...
   ParamX = 1;
   ParamY = 0;
   Text = NULL;
   Primary = NULL;

   // For each argument...
   for (i = 0; i < argc; i++)
      {
      // Get the next argument and see what it is
      Arg = argv[i];
      switch (Arg[0])
         {
         case '-':
         case '/':
            // It's an argument; which one?
            switch (Arg[1])
               {
               case '?':
               case 'h':
               case 'H':
                  // A cry for help
                  printf ("Usage:  whatever...\n\n");
                  return (0);
                  break;

               case 't':
               case 'T':
                  // Param T requires a value; is it there?
                  i++;
                  if (i >= argc)
                     {
                     printf ("Error:  missing value after '%s'.\n\n", Arg);
                     return (1);
                     }

                  // Just remember this
                  Text = Arg;

                  break;

               case 'x':
               case 'X':
                  // Param X requires a value; is it there?
                  i++;
                  if (i >= argc)
                     {
                     printf ("Error:  missing value after '%s'.\n\n", Arg);
                     return (1);
                     }

                  // The value is there; get it and convert it to an int (1..10)
                  Arg = argv[i];
                  ParamX = atoi (Arg);
                  if ((ParamX == 0) || (ParamX > 10))
                     {
                     printf ("Error:  invalid value for '%s'; must be between 1 and 10.\n\n", Arg);
                     return (1);
                     }

                  break;

               case 'y':
               case 'Y':
                  // Param Y doesn't expect a value after it
                  ParamY = 1;
                  break;

               default:
                  // Unexpected argument
                  printf ("Error:  unexpected parameter '%s'; type 'command -?' for help.\n\n", Arg);
                  return (1);
                  break;
               }

            break;

         default:
            // It's not a switch that begins with '-' or '/', so it's the primary option
            Primary = Arg;

            break;
         }
      }

   // Done
   return (0);
   }

Я цитирую ответ ANTLR от mes5k.Этот ссылка на кодпроект предназначена для статьи, в которой обсуждается ANLTR и использование шаблона посещения для реализации действий, которые вы хотите, чтобы приложение выполняло.Это хорошо написано и заслуживает внимания.

Я бы рекомендовал использовать библиотеку процессора командной строки. Какой-то русский парень создал приличный, но их там масса.Это сэкономит вам некоторое время, и вы сможете сосредоточиться на цели вашего приложения, а не на анализе ключей командной строки!

Getopt — единственный путь.

http://sourceforge.net/projects/charpoptparse

Как насчет шаблона переводчика?http://www.dofactory.com/net/interpreter-design-pattern

Вы не упомянули язык для этого, но если вы ищете действительно хорошую оболочку Objective-C для getopt, то структура DDCLI Дэйва Дрибина действительно хороша.

http://www.dribin.org/dave/blog/archives/2008/04/29/ddcli

Я использую Getopts::std и Getopts::long в Perl, а также Получить функция в С.Это стандартизирует синтаксический анализ и формат параметров.Другие языки имеют разные механизмы для их обработки.

Надеюсь это поможет

Стандартный дизайн обычно соответствует тому, что делает getopt: существуют библиотеки getopt для многих языков, .NET, Python, C, Perl, PHP и т. д.

Базовая конструкция заключается в наличии анализатора командной строки, который по частям возвращает переданные аргументы для проверки в цикле.

Этот в статье это обсуждается более подробно.

Библиотеки меня не особо интересуют, хотя это определенно полезно.Я больше искал какой-нибудь «псевдокод», который иллюстрирует обработку, скажем, вашего среднего набора флагов и набора более длинных аргументов, например.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top