处理命令行参数的设计模式是什么
如果要编写可从命令行执行的程序,则通常要向用户提供几个选项或者标志以及可能不止一个参数。我已经无数次地迷失了自己的方式,但是是否存在某种用于遍历args并调用适当的处理函数的设计模式?
考虑:
myprogram -f filename -d directory -r regex
使用适用于语言的内置函数检索参数后,如何组织处理程序函数? (欢迎使用针对特定语言的答案,如果可以明确说明答案)
解决方案
回答
我不知道要处理任何记录的"模式"。
我相信用于处理参数的最古老的库/ API之一是getopt。谷歌搜索" getopt"显示了许多手册页以及实现的链接。
通常,我的应用程序中有一个首选项或者设置服务,参数处理器知道如何与之通信。然后将参数转换为该服务中的某个内容,然后由应用程序进行查询。这可以像设置字典一样简单(例如,名为"文件名"的字符串设置)。
回答
我建议使用命令行处理器库。一些俄罗斯人创造了一个像样的人,但那里有很多人。这将节省我们一些时间,因此我们可以专注于应用程序的用途,而不用解析命令行开关!
回答
我们没有提到该语言,但是对于Java,我们喜欢Apache Commons CLI。对于C / C ++,请使用getopt。
回答
我们没有提到这种语言,但是如果我们正在寻找一个围绕getopt的非常好的Objective-C包装器,那么Dave Dribin的DDCLI框架就非常不错。
http://www.dribin.org/dave/blog/archives/2008/04/29/ddcli
回答
我在perl中使用Getopts :: std和Getopts :: long,在C语言中也使用Getopt函数。这标准化了参数的解析和格式。其他语言具有处理这些问题的不同机制。
希望这可以帮助
回答
标准设计通常遵循getopt所做的事情,有针对多种语言的getopt库,包括.NET,python,C,Perl,PHP等。
基本设计是具有一个命令行解析器,该解析器将部分返回循环传递的要检查的参数。
本文将对其进行更详细的讨论。
回答
Getopt是唯一的方法。
http://sourceforge.net/projects/csharpoptparse
回答
如果我们使用的是C ++并且可以轻松使用Boost,则boost :: program_options库非常有用。
回答
我对库的兴趣不大,但这绝对有帮助。我一直在寻找一些"伪代码",以举例说明我们处理平均一堆标志和一堆更长的参数的过程。
回答
假设我们有一个旨在使用标志进行设置的" 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 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); }
回答
关于此的一些评论...
首先,虽然本身没有任何模式,但是编写解析器本质上是一项机械练习,因为给定语法,可以轻松生成解析器。我想到了Bison和ANTLR等工具。
也就是说,解析器生成器通常对于命令行来说是多余的。因此,通常的模式是自己写几次(如其他人所展示的),直到我们厌倦了处理繁琐的细节并找到一个库来为我们做。
我为C ++编写了一个代码,它节省了getopt付出的大量工作并很好地利用了模板:TCLAP
回答
我正在通过mes5k仔细研究ANTLR的答案。该指向Codeproject的链接是用于讨论ANLTR以及如何使用访问模式来实现我们希望应用执行的操作的文章。它写得很好,值得回顾。