Pregunta

Si está escribiendo un programa ejecutable desde la línea de comandos, a menudo querrá ofrecer al usuario varias opciones o indicadores, junto con posiblemente más de un argumento.Me he encontrado con esto muchas veces, pero ¿existe algún tipo de patrón de diseño para recorrer argumentos y llamar a las funciones de controlador apropiadas?

Considerar:

myprogram -f filename -d directory -r regex

¿Cómo organiza las funciones del controlador después de recuperar los argumentos utilizando las funciones integradas de su idioma?(Se aceptan respuestas específicas del idioma, si eso le ayuda a articular una respuesta)

¿Fue útil?

Solución

No conozco ningún "patrón" documentado para el procesamiento.

Creo que una de las bibliotecas/API más antiguas para manejar argumentos es getopt.Buscar en Google "getopt" muestra muchas páginas de manual y enlaces a implementaciones.

Generalmente, tengo un servicio de preferencias o configuración en mi aplicación con el que el procesador de argumentos sabe cómo comunicarse.Luego, los argumentos se traducen en algo en este servicio que la aplicación luego consulta.Esto podría ser tan simple como un diccionario de configuraciones (como una configuración de cadena llamada "nombre de archivo").

Otros consejos

Creo que la siguiente respuesta se ajusta más a lo que estás buscando:

Debería considerar aplicar el patrón de plantilla (Método de plantilla en "Patrones de diseño" [Gamma, el al])

En resumen, su procesamiento general se ve así:

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

En resumen, implemente una clase ConsoleEngineBase que tenga métodos para:

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

Luego cree un chasis que cree una instancia de ConsoleEngine() y envíe el mensaje Main() para iniciarla.

Para ver un buen ejemplo de cómo aplicar esto a una consola o programa de línea de comandos, consulte el siguiente enlace:http://msdn.microsoft.com/en-us/magazine/cc164014.aspx

El ejemplo está en C#, pero las ideas se implementan fácilmente en cualquier otro entorno.

Consideraría GetOpt() simplemente la parte que encaja en el manejo de argumentos (preprocesamiento).

Espero que esto ayude.

No mencionaste el idioma, pero para Java nos encantó. CLI de Apache Commons.Para C/C++, opte.

Algunos comentarios sobre esto...

En primer lugar, si bien no existen patrones per se, escribir un analizador es esencialmente un ejercicio mecánico, ya que, dada una gramática, se puede generar fácilmente un analizador.Me vienen a la mente herramientas como Bison y ANTLR.

Dicho esto, los generadores de analizadores suelen ser excesivos para la línea de comandos.Entonces, el patrón habitual es escribir uno usted mismo (como otros han demostrado) varias veces hasta que se canse de lidiar con los detalles tediosos y encuentre una biblioteca que lo haga por usted.

Escribí uno para C++ que ahorra mucho esfuerzo y que getopt imparte y hace un buen uso de las plantillas: TCLAP

Bueno, es una publicación antigua pero todavía me gustaría contribuir.La pregunta tenía como objetivo la elección de patrones de diseño, sin embargo, pude ver mucha discusión sobre qué biblioteca usar.Revisé el enlace de Microsoft según Lindsay, que habla sobre el patrón de diseño de plantilla a usar.

Sin embargo, no estoy convencido con la publicación.La intención del patrón de plantilla es definir una plantilla que será implementada por otras clases para tener un comportamiento uniforme.No creo que el análisis de la línea de comando encaje en esto.

Prefiero optar por el patrón de diseño "Comando".Este patrón se adapta mejor a las opciones controladas por menú.

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

entonces, en su caso, -f, -d y -r se convierten en comandos que tienen definido un receptor común o separado.De esta manera se podrán definir más receptores en el futuro.El siguiente paso será encadenar estas responsabilidades de los comandos, en caso de que se requiera una cadena de procesamiento.Por el cual elegiría.

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

Supongo que la combinación de estos dos es mejor para organizar el código para el procesamiento de la línea de comandos o cualquier enfoque basado en menús.

El impulso::opciones_programas La biblioteca es buena si estás en C++ y tienes el lujo de usar Boost.

Suponiendo que tiene un objeto "config" que desea configurar con las banderas y un analizador de línea de comando adecuado que se encarga de analizar la línea de comando y proporciona un flujo constante de opciones, aquí va un bloque de pseudocódigo

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;
    }
}

Prefiero opciones como "-t texto" y "-i 44";No me gusta "-fname" o "--very-long-argument=some_value".

Y "-?", "-h" y "/h" generan una pantalla de ayuda.

Así es como se ve mi código:

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);
   }

Estoy basándose en la respuesta ANTLR de mes5k.Este enlace al proyecto de código es para un artículo que analiza ANLTR y el uso del patrón de visita para implementar las acciones que desea que realice su aplicación.Está bien escrito y vale la pena revisarlo.

Recomendaría utilizar una biblioteca de procesador de línea de comandos. Algún chico ruso Creé uno decente, pero hay toneladas de ellos por ahí.¡Le ahorrará algo de tiempo para que pueda concentrarse en el propósito de su aplicación en lugar de analizar cambios en la línea de comandos!

Getopt es el único camino a seguir.

http://sourceforge.net/projects/csharpoptparse

¿Qué tal el patrón de intérprete?http://www.dofactory.com/net/interpreter-design-pattern

No mencionas un lenguaje para esto, pero si estás buscando un contenedor Objective-C realmente bueno para getopt, entonces el marco DDCLI de Dave Dribin es realmente bueno.

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

Yo uso el Getopts::std y Getopts::largo en perl y también el Optar función en C.Esto estandariza el análisis y el formato de los parámetros.Otros idiomas tienen diferentes mecanismos para manejarlos.

Espero que esto ayude

El diseño estándar suele seguir lo que hace getopt, existen bibliotecas getopt para muchos lenguajes, .NET, python, C, Perl, PHP, etc.

El diseño básico es tener un analizador de línea de comando que devuelve parte por parte los argumentos pasados ​​para verificarlos en un bucle.

Este El artículo lo analiza con más detalle.

No estoy tan interesado en las bibliotecas, aunque eso definitivamente es útil.Estaba buscando más algún "pseudocódigo" que ilustre el procesamiento de, digamos, un grupo promedio de indicadores y un montón de argumentos más largos, como ejemplo.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top