如果程序被指定像这样运行,那么在c++中解析命令行参数的最佳方式是什么:
prog [-abc] [input [output]]
是否有某种方法可以在标准库中实现这一点,或者我需要自己编写代码?
相关:
在unicode c++应用程序中解析命令行参数
如果程序被指定像这样运行,那么在c++中解析命令行参数的最佳方式是什么:
prog [-abc] [input [output]]
是否有某种方法可以在标准库中实现这一点,或者我需要自己编写代码?
相关:
在unicode c++应用程序中解析命令行参数
当前回答
您可以使用GNU GetOpt (LGPL)或各种c++端口之一,例如getoptpp (GPL)。
一个简单的例子使用GetOpt你想要的东西(prog [-ab] input)如下:
// C Libraries:
#include <string>
#include <iostream>
#include <unistd.h>
// Namespaces:
using namespace std;
int main(int argc, char** argv) {
int opt;
string input = "";
bool flagA = false;
bool flagB = false;
// Retrieve the (non-option) argument:
if ( (argc <= 1) || (argv[argc-1] == NULL) || (argv[argc-1][0] == '-') ) { // there is NO input...
cerr << "No argument provided!" << endl;
//return 1;
}
else { // there is an input...
input = argv[argc-1];
}
// Debug:
cout << "input = " << input << endl;
// Shut GetOpt error messages down (return '?'):
opterr = 0;
// Retrieve the options:
while ( (opt = getopt(argc, argv, "ab")) != -1 ) { // for each option...
switch ( opt ) {
case 'a':
flagA = true;
break;
case 'b':
flagB = true;
break;
case '?': // unknown option...
cerr << "Unknown option: '" << char(optopt) << "'!" << endl;
break;
}
}
// Debug:
cout << "flagA = " << flagA << endl;
cout << "flagB = " << flagB << endl;
return 0;
}
其他回答
它太大了,不可能包含在Stack Overflow回答中,但我创建了一个用于声明式定义命令行的库。它利用了c++ 14通过给每个成员变量赋初始值来构建类构造函数的能力。
这个库基本上是一个基类。要定义命令语法,需要声明一个派生自该语法的结构。下面是一个例子:
struct MyCommandLine : public core::CommandLine {
Argument<std::string> m_verb{this, "program", "program.exe",
"this is what my program does"};
Option<bool> m_help{this, "help", false,
"displays information about the command line"};
Alias<bool> alias_help{this, '?', &m_help};
Option<bool> m_demo{this, "demo", false,
"runs my program in demonstration mode"};
Option<bool> m_maximize{this, "maximize", false,
"opens the main window maximized"};
Option<int> m_loops{this, "loops", 1,
"specifies the number of times to repeat"};
EnumOption<int> m_size{this, "size", 3,
{ {"s", 1},
{"small", 1},
{"m", 3},
{"med", 3},
{"medium", 3},
{"l", 5},
{"large", 5} } };
BeginOptionalArguments here{this};
Argument<std::string> m_file{this, "file-name", "",
"name of an existing file to open"};
} cl;
参数、选项和别名类模板是在CommandLine基类的范围内声明的,您可以为自己的类型专门化它们。每个选项都包含this指针、选项名称、默认值和用于打印命令概要/用法的描述。
我仍然在寻找消除所有这些指针的需要,但我还没有找到一种不引入宏的方法。这些指针允许每个成员向驱动解析的基类中的表注册自己。
一旦有了实例,就会有多个方法重载来解析来自字符串或主样式参数向量的输入。解析器同时处理windows风格和unix风格的选项语法。
if (!cl.Parse(argc, argv)) {
std::string message;
for (const auto &error : cl.GetErrors()) {
message += error + "\n";
}
std::cerr << message;
exit(EXIT_FAILURE);
}
一旦它被解析,你可以使用operator()访问任何选项的值:
if (cl.m_help()) { std::cout << cl.GetUsage(); }
for (int i = 0; i < cl.m_loops(); ++i) { ... }
整个库只有大约300行(不包括测试)。实例有点臃肿,因为解析表是实例(而不是类)的一部分。但是每个程序通常只需要一个实例,而且这种纯声明性方法的便利性非常强大,可以通过解析新输入简单地重置实例。
Argstream与boost非常相似。Program_option:它允许将变量绑定到选项等。但是,它不处理存储在配置文件中的选项。
一个简单的解决方案是将argv放入std::map中,以便查找:
map<string, string> argvToMap(int argc, char * argv[])
{
map<string, string> args;
for(int i=1; i<argc; i++) {
if (argv[i][0] == '-') {
const string key = argv[i];
string value = "";
if (i+1 < argc && argv[i+1][0] != '-') {
value = string(argv[i+1]);
i++;
}
args[key] = value;
}
}
return args;
}
使用示例:
#include <map>
#include <string>
#include <iostream>
using namespace std;
map<string, string> argvToMap(int argc, char * argv[])
{
map<string, string> args;
for(int i=1; i<argc; i++) {
if (argv[i][0] == '-') {
const string key = argv[i];
string value = "";
if (i+1 < argc && argv[i+1][0] != '-') {
value = string(argv[i+1]);
i++;
}
args[key] = value;
}
}
return args;
}
void printUsage()
{
cout << "simple_args: A sample program for simple arg parsing\n"
"\n"
"Example usage:\n"
" ./simple_args --print-all --option 1 --flag 2\n";
}
int main(int argc, char * argv[])
{
auto args = argvToMap(argc, argv);
if (args.count("-h") || args.count("--help")) {
printUsage();
}
else if (args.count("--print-all")) {
for (auto const & pair: args)
cout << "{" << pair.first << ": " << pair.second << "}\n";
}
return 0;
}
输出:
$ ./simple_args --print-all --option 1 --flag "hello world"
{--flag: hello world}
{--option: 1}
{--print-all: }
这种方法肯定有很大的局限性,但我发现它很好地平衡了简单性和实用性。
您可以为此使用已经创建的库
http://www.boost.org/doc/libs/1_44_0/doc/html/program_options.html
我在一些项目中使用过GetPot: http://getpot.sourceforge.net/
主要特点:所有东西都在一个头文件中,没有构建的麻烦。只需将它保存在你机器上的某个地方,并在你的文件中使用main()
最近没有更新,但它有很好的文档记录,工作得很好。