如果指定了程序,在C ++中解析命令行参数的最佳方法是什么 像这样运行:
prog [-abc] [input [output]]
STL中是否有库来执行此操作?
相关:
答案 0 :(得分:221)
boost::program_options
和GNU getopt的建议很好。
但是,对于简单的命令行选项,我倾向于使用std :: find
例如,在-f
命令行参数后读取文件名。您还可以检测是否已传递单字选项,如-h
以获取帮助。
#include <algorithm>
char* getCmdOption(char ** begin, char ** end, const std::string & option)
{
char ** itr = std::find(begin, end, option);
if (itr != end && ++itr != end)
{
return *itr;
}
return 0;
}
bool cmdOptionExists(char** begin, char** end, const std::string& option)
{
return std::find(begin, end, option) != end;
}
int main(int argc, char * argv[])
{
if(cmdOptionExists(argv, argv+argc, "-h"))
{
// Do stuff
}
char * filename = getCmdOption(argv, argv + argc, "-f");
if (filename)
{
// Do interesting things
// ...
}
return 0;
}
在使用这种方法注意的事项上,必须使用std :: strings作为std :: find的值,否则对指针值执行相等性检查。
我希望可以编辑此响应而不是添加新响应,因为这是基于原始答案。我稍微重写了函数并将它们封装在一个类中,所以这里是代码。我认为以这种方式使用也是可行的:
class InputParser{
public:
InputParser (int &argc, char **argv){
for (int i=1; i < argc; ++i)
this->tokens.push_back(std::string(argv[i]));
}
/// @author iain
const std::string& getCmdOption(const std::string &option) const{
std::vector<std::string>::const_iterator itr;
itr = std::find(this->tokens.begin(), this->tokens.end(), option);
if (itr != this->tokens.end() && ++itr != this->tokens.end()){
return *itr;
}
static const std::string empty_string("");
return empty_string;
}
/// @author iain
bool cmdOptionExists(const std::string &option) const{
return std::find(this->tokens.begin(), this->tokens.end(), option)
!= this->tokens.end();
}
private:
std::vector <std::string> tokens;
};
int main(int argc, char **argv){
InputParser input(argc, argv);
if(input.cmdOptionExists("-h")){
// Do stuff
}
const std::string &filename = input.getCmdOption("-f");
if (!filename.empty()){
// Do interesting things ...
}
return 0;
}
答案 1 :(得分:81)
Boost.Program_options应该做的伎俩
答案 2 :(得分:57)
我可以建议Templatized C++ Command Line Parser Library(某些forks on GitHub可用),API非常简单并且(从网站引用):
库完全在头文件中实现,使其变得容易 使用和分发其他软件。它是在麻省理工学院获得许可的 无忧分发许可证。
这是手册中的一个示例,为简单起见,此处着色:
#include <string>
#include <iostream>
#include <algorithm>
#include <tclap/CmdLine.h>
int main(int argc, char** argv)
{
// Wrap everything in a try block. Do this every time,
// because exceptions will be thrown for problems.
try {
// Define the command line object, and insert a message
// that describes the program. The "Command description message"
// is printed last in the help text. The second argument is the
// delimiter (usually space) and the last one is the version number.
// The CmdLine object parses the argv array based on the Arg objects
// that it contains.
TCLAP::CmdLine cmd("Command description message", ' ', "0.9");
// Define a value argument and add it to the command line.
// A value arg defines a flag and a type of value that it expects,
// such as "-n Bishop".
TCLAP::ValueArg<std::string> nameArg("n","name","Name to print",true,"homer","string");
// Add the argument nameArg to the CmdLine object. The CmdLine object
// uses this Arg to parse the command line.
cmd.add( nameArg );
// Define a switch and add it to the command line.
// A switch arg is a boolean argument and only defines a flag that
// indicates true or false. In this example the SwitchArg adds itself
// to the CmdLine object as part of the constructor. This eliminates
// the need to call the cmd.add() method. All args have support in
// their constructors to add themselves directly to the CmdLine object.
// It doesn't matter which idiom you choose, they accomplish the same thing.
TCLAP::SwitchArg reverseSwitch("r","reverse","Print name backwards", cmd, false);
// Parse the argv array.
cmd.parse( argc, argv );
// Get the value parsed by each arg.
std::string name = nameArg.getValue();
bool reverseName = reverseSwitch.getValue();
// Do what you intend.
if ( reverseName )
{
std::reverse(name.begin(),name.end());
std::cout << "My name (spelled backwards) is: " << name << std::endl;
}
else
std::cout << "My name is: " << name << std::endl;
} catch (TCLAP::ArgException &e) // catch any exceptions
{ std::cerr << "error: " << e.error() << " for arg " << e.argId() << std::endl; }
}
答案 3 :(得分:32)
您可以使用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;
}
答案 4 :(得分:21)
另一个替代方案是精益平均C ++选项解析器:
http://optionparser.sourceforge.net
它是一个仅限标题的库(实际上只是一个头文件),与其他所有建议不同 也是独立的,即它没有任何依赖性。特别是对STL没有依赖性。它甚至不使用需要库支持的异常或其他任何东西。这意味着它可以与普通的C或其他语言链接而不引入“外国”库。
与boost :: program_options类似,它的API提供了方便的直接访问选项, 即你可以写这样的代码
if(options [HELP])...;
和
int verbosity = options [VERBOSE] .count();
与boost :: program_options不同,这只是使用一个用(用户提供的)枚举索引的数组。这提供了一个没有重量的关联容器的便利。
它有详细记录并且拥有公司友好许可证(MIT)。
TLMC ++ OP包含一个很好的格式化程序,可用于使用消息 换行和列对齐,这对于本地化程序很有用,因为它确保即使在具有较长消息的语言中输出也会很好。它还可以节省您手动格式化80列使用情况的麻烦。
答案 5 :(得分:10)
for (int i = 1; i < argc; i++) {
if (strcmp(argv[i],"-i")==0) {
filename = argv[i+1];
printf("filename: %s",filename);
} else if (strcmp(argv[i],"-c")==0) {
convergence = atoi(argv[i + 1]);
printf("\nconvergence: %d",convergence);
} else if (strcmp(argv[i],"-a")==0) {
accuracy = atoi(argv[i + 1]);
printf("\naccuracy:%d",accuracy);
} else if (strcmp(argv[i],"-t")==0) {
targetBitRate = atof(argv[i + 1]);
printf("\ntargetBitRate:%f",targetBitRate);
} else if (strcmp(argv[i],"-f")==0) {
frameRate = atoi(argv[i + 1]);
printf("\nframeRate:%d",frameRate);
}
}
答案 6 :(得分:5)
AnyOption是一个C ++类,用于轻松解析复杂的命令行选项。它还以选项值对格式解析rsourcefile中的选项。
AnyOption实现了传统的POSIX样式字符选项(-n)以及较新的GNU样式长选项(--name)。或者,您可以通过要求忽略POSIX样式选项来使用更简单的长选项版本(-name)。
答案 7 :(得分:3)
如果你可以使用Boost lib,我建议使用boost :: program_options。
STL和常规C ++ / C运行时库中没有任何特定内容。
答案 8 :(得分:2)
尝试CLPP库。它是用于命令行参数解析的简单而灵活的库。仅限标题和跨平台。仅使用ISO C ++和Boost C ++库。恕我直言,它比Boost.Program_options更容易。
图书馆:http://sourceforge.net/projects/clp-parser
2010年10月26日 - 新版本2.0rc。修复了许多错误,修改了源代码,文档,示例和注释的完全重构。
答案 9 :(得分:2)
很晚才回答,但我在一些项目中使用了GetPot: http://getpot.sourceforge.net/
主要功能:一切都在一个头文件中,没有构建麻烦。只需将其保存在计算机上的某个位置,然后将“#include”保存在包含main()
最近没有更新,但很好地记录,并且运作良好。你可以尝试一下。
答案 10 :(得分:-1)
一个简单的解决方案是将 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: }
这种方法肯定有很大的局限性,但我发现它在简单性和实用性之间取得了很好的平衡。