如果您正在编写一个可从命令行执行的程序,您通常希望为用户提供多个选项或标志,以及可能的多个参数。我已经多次遇到这个问题,但是是否有某种设计模式可以循环 args 并调用适当的处理函数?

考虑:

myprogram -f filename -d directory -r regex

使用适合您的语言的任何内置函数检索参数后,如何组织处理程序函数?(欢迎特定语言的答案,如果这有助于您阐明答案)

有帮助吗?

解决方案

我不知道有任何记录的处理“模式”。

我相信用于处理参数的最古老的库/API 之一是 getopt。谷歌搜索“getopt”显示大量手册页和实现链接。

一般来说,我的应用程序中有一个首选项或设置服务,参数处理器知道如何与之通信。然后,参数被转换为该服务中的内容,然后应用程序可以查询。这可以像设置字典一样简单(例如名为“文件名”的字符串设置)。

其他提示

我认为以下答案更符合您正在寻找的内容:

您应该考虑应用模板模式(“设计模式”中的模板方法[Gamma,等])

简而言之,它的整体处理过程如下:

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 CLI. 。对于 C/C++,getopt。

对此的一些评论...

首先,虽然本身没有任何模式,但编写解析器本质上是一种机械练习,因为给定语法,可以轻松生成解析器。我想到了 Bison 和 ANTLR 等工具。

也就是说,解析器生成器对于命令行来说通常是多余的。因此,通常的模式是自己编写一个(正如其他人已经演示的那样)几次,直到您厌倦了处理繁琐的细节并找到一个库来为您完成它。

我为 C++ 编写了一个,它节省了 getopt 带来的大量精力,并且很好地利用了模板: TCLAP

嗯,这是一篇旧文章,但我仍然想做出贡献。这个问题的目的是选择设计模式,但是我可以看到很多关于使用哪个库的讨论。我已经根据 Lindsay 查看了 microsoft 链接,其中讨论了要使用的模板设计模式。

然而,我对这篇文章并不信服。模板模式的目的是定义一个模板,该模板将由各种其他类实现以具有统一的行为。我认为解析命令行不适合它。

我宁愿选择“命令”设计模式。此模式最适合菜单驱动的选项。

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

因此,在您的情况下,-f、-d 和 -r 都成为定义了公共或单独接收器的命令。这样将来可以定义更多的接收器。下一步将是链接命令的这些职责,以防需要处理链。我会选择哪个。

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

我想这两者的组合最适合组织命令行处理或任何菜单驱动方法的代码。

升压::程序选项 如果您使用 C++ 并且可以使用 Boost,那么这个库就很好。

假设您有一个“配置”对象,您的目标是使用标志和合适的命令行解析器来设置它,该解析器负责解析命令行并提供恒定的选项流,这里有一段伪代码

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 text”和“-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);
   }

我正在重复 mes5k 的 ANTLR 答案。这 链接到代码项目 是一篇讨论 ANLTR 并使用访问模式来实现您希望应用程序执行的操作的文章。写得很好,值得回顾。

我建议使用命令行处理器库。 某个俄罗斯小伙子 创建了一个不错的,但有很多这样的。将为您节省一些时间,以便您可以专注于应用程序的用途,而不是解析命令行开关!

Getopt 是唯一的出路。

http://sourceforge.net/projects/csharpoptparse

你没有提到这方面的语言,但如果你正在寻找一个非常好的围绕 getopt 的 Objective-C 包装器,那么 Dave Dribin 的 DDCLI 框架非常好。

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

我用 获取选择::std获取选择::长 在 Perl 中以及 吉奥普 C 中的函数。这标准化了参数的解析和格式。其他语言有不同的机制来处理这些问题。

希望这可以帮助

标准设计通常遵循 getopt 的做法,有多种语言的 getopt 库,.NET、python、C、Perl、PHP 等。

基本设计是有一个命令行解析器,它逐部分返回传递给循环检查的参数。

文章更详细地讨论了它。

我对图书馆不太感兴趣,尽管这绝对有帮助。作为一个例子,我更多地寻找一些“伪代码”来说明你的平均标志和一堆较长参数的处理。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top