如果程序指定以这种方式运行,那么在C++中解析命令行参数的最佳方法是什么:
prog [-abc] [input [output]]
标准库中是否有实现这个功能的方法,还是我需要编写自己的代码?
相关问题:
如果程序指定以这种方式运行,那么在C++中解析命令行参数的最佳方法是什么:
prog [-abc] [input [output]]
标准库中是否有实现这个功能的方法,还是我需要编写自己的代码?
相关问题:
关于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;
}
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;
}
const std::string&
。很重要的一点是,传入std::find
函数的值参数必须是一个std::string
类型,这样才会使用std::string :: operator==()
,而不是char * operator==()
(后者仅比较指针值而不是字符串内容)。 - iaintar -xf file
,对吗?每个选项必须分开。grep -ln pattern file
不能被理解,应该是 grep -l -n pattern file
。 - lmat - Reinstate MonicagetCmdOption
返回空字符串时。 InputParser
应该拥有一个名为 std::string empty_string
的成员,并在选项未找到时返回其引用。Boost.Program_options 可以解决问题。
该库完全以头文件的形式实现,易于与其他软件一起使用和分发。它在MIT许可证下授权,可无忧地进行分发。
这是手册中的一个示例,此处为了简洁起见进行了颜色处理:
#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; }
}
options.add_options()(option1)(option2)...
这样的措辞,我认为这是对C++语法的滥用。 - gatopeich--long-option
这样的东西,自己做起来相当简单。 - Luis Machucaboost::program_options
过度设计,使用难度大,文档不足。这是少数几个 Boost 库之一,非常需要完全重新设计和重写。如果可以避免使用,请不要使用它。 - András Aszódi你可以使用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;
}
GNU GetOpt。
使用 GetOpt 的简单示例:
// C/C++ Libraries:
#include <string>
#include <iostream>
#include <unistd.h>
// Namespaces:
using namespace std;
int main(int argc, char** argv) {
int opt;
bool flagA = false;
bool flagB = false;
// 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;
}
如果您有需要接受参数的选项,您还可以使用optarg。
另一个选择是The Lean Mean C++ Option Parser:
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列。
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);
}
}
argv[i+1]
的引用可能会轻易地超出argv
数组的边界。考虑以"-i"
作为最后一个参数运行程序。 - Keith ThompsonTCLAP
是一个非常好的轻量级设计,易于使用:
http://tclap.sourceforge.net/
如果您只想自己处理命令行选项,最简单的方法是将以下内容放入:
vector<string> args(argv + 1, argv + argc);
在你的main()
函数的顶部。这将所有命令行参数复制到一个std::string
向量中。然后,您可以使用==
轻松比较字符串,而不是无尽的strcmp()
调用。例如:
int main(int argc, char **argv) {
vector<string> args(argv + 1, argv + argc);
string infname, outfname;
// Loop over command-line args
// (Actually I usually use an ordinary integer loop variable and compare
// args[i] instead of *i -- don't tell anyone! ;)
for (auto i = args.begin(); i != args.end(); ++i) {
if (*i == "-h" || *i == "--help") {
cout << "Syntax: foomatic -i <infile> -o <outfile>" << endl;
return 0;
} else if (*i == "-i") {
infname = *++i;
} else if (*i == "-o") {
outfname = *++i;
}
}
}
[编辑:我意识到我正在复制程序的名称argv[0]
到args
中,已经修复。]
mycommand.exe -h file.csv
,我想告诉他们他们没有正确使用实用程序以及为什么(如果他们只是使用版本,则不应提供文件名)。这个例子相当简单,但我可以想到更复杂的标志。最终结果将是:有时顺序很重要,有时不重要。那么...我该怎么办呢?如果您对我的问题有疑问,请告诉我。 - Hamish Grubijanargs[i]
访问第i个参数(事实上,我经常这样做,正如我代码片段中的注释所说)。如果您只需要一次处理一个参数,则迭代器样式会更方便一些。这回答了您的问题吗? - j_random_hacker
getopt
或argparse
。 - Andrejs Cainikovsstd :: vector <std :: string> args(argv,argv + argc);
,以便您可以解析字符串向量而不是字符数组。 - stefaanv