一个简单易用的C++命令行分析器 SmpCommandLine

一个简单易用的C++命令行分析器 SmpCommandLine

凡事都要从简单开始,这篇文章就介绍一个简易的命令行分析器 SmpCommandLine 吧。

SmpCommandLine 是一个轻量级的 C++ 程序包,用于提取用户在命令行输入的参数。

世界上已经有很多命令行分析工具了,比如 C 标准库的 getopt,Google 的 C++ 库 gflags 等,其中也不乏一些易用的库,不过很多 C/C++ 程序员都有一个“怪癖”,喜欢重新发明和制作轮子。

SmpCommandLine 的特点是比较简单易用,不过它目前只支持 C++ 语言(并且暂时只在Ubuntu 上测试过,但很可能也可以用于Windows)。这个工具只包含一个短小的头文件,代码可以在 github上获取

1. 极简版用法

真正简单易用的东西,说明文档也应该简练易懂,否则光阅读和理解说明文档的功夫,都可以写出自己的方案来了。对于足够简单的工具程序,最好的说明文档,就是直接来一段示例代码。

SmpCommandLine 极简版的使用方法示例:

#include "SmpCommandLine.hpp"
int main( int argc, char *argv[] )
{
    SmpCommandLine commands( argc, argv );
    
    int  imageWidth = commands.getInteger( "w", NULL );
    bool bShowImage = commands.getBoolean( "s", NULL );
    std::string outputFileName = commands.getString( "o", NULL );
    std::string inputFileName  = commands.getString( 1 );
    // ...
}

你只需从 GitHub 下载 SmpCommandLine.hpp,把 SmpCommandLine.hpp 放到你的 C++ 项目中,在你的 main 函数所在的 cpp 文件里包含它,并在 main 函数头部加上类似上述例子的几行代码,即可从用户的命令行输入中获取你想获取的参数。上述示例代码中,首先创建一个 SmpCommandLine 对象,注意在构造函数中要传入arc 和 argv 从 main 入口中传来的两个参数,然后调用

 getInteger( "w", ...)
 getBoolean( "s", ...)
 getString( "o", ...) 

等方法分别提取带有-w、-s、-o 标志的参数,方法名中的 …Integer、…Boolean、…String 表示该方法返回值的类型。最后调用

 getString( 1, ... ) 

提取第一个无标志的参数。程序编译后,当用户在终端输入如下命令行参数时:

 $./my_program source_photo.jpg -o target_photo.jpg -w 720 -s

程序中的变量被赋予如下值:

 inputFileName  = "source_photo.jpg"
 outputFileName = "target_photo.jpg"
 imageWidth     = 720
 bShowImage     = true

这个例子中,用户输入的第一个参数(即跟在可执行程序名后面的第一个参数 source_ photo.jpg)是不带标志的,后面的几个参数是带标志的参数。(这里带标志的参数是指,比如像"-o target_photo.jpg" 这样的由一个单横杆“-”或双横杆"–"开始的标志字符或单词以及跟在后面的参数。)

2. 带标志参数和无标志参数

这里稍微插入说明一下,带标志的命令行参数和不带标志的命令行参数。带标志的命令行参数由单横杆“-”引领的短标志开始(如 “-o"、"-f" 之类),或由双横杆引领的长标志开始(如 “–output”、"–filter_name" 之类),后面跟着一个表示该参数的值的字符串(可选)。比如对于上面的例子,当用户输入命令行中含有 “-o target_photo.jpg” 或 “–output target_photo.jpg" 时, “target_photo.jpg” 是 “-o” 或 “–output” 所对应参数的值。带标志的参数由于有标志做识别,不会和别的参数混淆,所以用户在输入命令行时,可以将它们插入在参数表中的任何地方。

在带标志的参数中,如果该参数表示的是布尔变量,在标志后面可以不跟表示变量值的参数。比如上述例子中的“-s",当这个标志出现在命令行中时,bShowImage 被赋值为 true,否则, bShowImage 被设为缺省值 false。

另一种是无标志的参数,无标志参数必须按照固定的顺序出现在命令行参数表中才能被程序辨认。比如上述例子中,用户在命令行输入的 “source_photo.jpg" ,它必须放在可执行程序名后面除去所有带标志参数外的第 1 个参数的位置。又比如我们常用的 g++ 的编译命令: “g++ SmpCommandLine_Demo.cpp -o my_program” 中 ,前面的 SmpCommandLine_Demo.cpp 是不带标志的参数,用于指定输入文件名,后面 “-o my_program” 是带标志的参数,表示输出的可执行文件名。

这里有一个需要特别注意的地方,由于在提取参数之前, SmpCommandLine 并不知道某个标志位之后是否跟有一个表示值的参数,所以

在调用 SmpCommandLine 提取参数时,要先提取完所有带标志的参数后,再提取无参数的参数

比如上面的例子中,下面一句要放在最后:

 string inputFileName  = commands.getString( 1 );

即在提取完所有带标志的参数(-w, -s, -o) 之后,再在剩余的命令行字符串中提取第一个无标志参数(否则程序会有报错提醒)。

上面是简单版的用法,下面我们看看完整版的用法:

3. 完整版用法

同样先来段示例代码:

#include "SmpCommandLine.hpp"
using namespace std;

int main( int argc, char *argv[] )
{
    SmpCommandLine userCommands( argc, argv );

    // Firstly extract all flagged argumants (i.e. argument identified by a leading hyphen flag)
    int  index = userCommands.getInteger( "i", "index", 0, "specifies the index of the item" );
    double radius = userCommands.getDouble( "r", "radius", 6750.0, "the radius of the shpere" ); 
    bool bShowImage = userCommands.getBoolean( "s", "show_image", CMD_FLAG_ONLY, false, "whether display the image during processing" );
    string filterName = userCommands.getString( "f", "filter", "", "specifies the image effect filter" );
    // Then, extract unflagged arguments:
    string srcFileName = userCommands.getString( 1, "", "file name of the source image" );
    string tgtFileName = userCommands.getString( 2, "", "file name of the target image" );
    // Check whether need to show help message:
    if( userCommands.helpMessageWanted() || argc < 3 ) {
        userCommands.showHelpMessage();
    }
    // Print the extracted arguments
    cout << "index = "  << index << endl;
    cout << "radius = " << radius << endl;
    cout << "bShowImage = " << bShowImage << endl;
    cout << "description : " << description << endl;
    cout << "srcFileName : " << srcFileName << endl;
    cout << "tgtFileName : " << tgtFileName << endl;

return(0);
}

这个例子中,在调用 SmpCommandLine 的接口方法时,除了指明该命令行参数的标志符或位置, 同时指定了参数变量的缺省值,以及关于这个参数用法的帮助信息。

比如,下面这个 getString() 方法在用户输入的命令行中寻找以 “-f” 或 “–filter” 标志符引出来的参数,并把它赋给一个叫 filterName 的字符串变量:

string filterName = userCommands.getString( "f", "filter", "", "specifies the image effect filter" );

这个方法的后面两个参数分别表示 filterName 的缺省值,以及这个命令行参数的帮助信息。

你可以用 getInteger() 、getFloat()、getDouble() 等方法分别获取用户输入的整型、浮点型和双精度浮点型参数。这些方法都有两个重载版本,分别用于提取带标志符的参数和无标识符的参数:

 // 提取带 -f 或 --filter 标志的命令行参数,返回字符串类型:
 string filterName = userCommands.getString( "f", "filter", "", "specifies the applied filter" );
 // 提取第 1 个无标志参数,返回字符串类型: 
 string srcFileName = userCommands.getString( 1, "", "file name of the source image" );

注意,用于提取带标志布尔参数的方法稍微有点特别,因为布尔参数的标志后面可以带表示值的参数也可以不带,为了指明该标志后面带不带额外参数,调用提取布尔参数的方法时,要传入 CMD_FLAG_ONLY (缺省)或 CMD_WITH_VALUE 作为说明:

 getBoolean( "s", "show_image", CMD_FLAG_ONLY, false, "whether display the image during processing" );

最后,在感觉到用户需要帮助时,调用下面代码显示命令行的帮助信息

  if( userCommands.helpMessageWanted() || argc < 3 ) {
        userCommands.showHelpMessage();
    }

这时,如果用户输入在命令行输入 $/ my_program --help (或-h),终端会显示以下帮助信息:

$>./my_program --help
Help Message: Usage of ./my_program
./my_program [argument1] [argument2] [-i/--index val] [-r/--radius val] [-s/--show_image] [-d/--description val] [-h/--help] 
    -i/--index val : specifies the index of the item (defualt value:0)
    -r/--radius val : the radius of the shpere (defualt value:6750.000000)
    -s/--show_image : whether display the image during processing (defualt value:false)
    -f/--filter val : specifies the applied image filter
    argument1: file name of the source image
    argument2: file name of the target image
    -h/--help : Show this help message (defualt value:false)

好了,总结一下:SmpCommandLine 是一个轻量级的 C++ 版命令行分析程序包,它的主要特点是:
1)它只有一个头文件,使用时只需在主函数所在的 cpp 文件中包含它即可;
2)它不需要提前先把所有参数规则(参数标志)列出来,而是一边提取所需的参数,一边构建参数规则,帮助信息则是从之前调用过的提取函数中收集信息自动合成而成;
3)使用时要注意先提取所有的带标志参数(带“-”的参数),再提取无标志参数;(这是这个程序包最不理想的地方,它是和第2点的权衡的结果)。

最后提一下,SmpCommandLine 中使用了STL标准库中的的 string、vector、algorithm 和 cctype 等。

更多的信息,可以参考 GitHub上 的 readme.md。

希望这碰巧对你有点用,并欢迎提出改进、优化的建议。Enjoy! 😊

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值