程序参数解析C/C++库 The Lean Mean C++ Option Parser
开发中我们经常使用程序参数,根据参数的不同来实现不同的功能。POSIX和GNU组织对此都制定了一些标准,为了我们程序更为通用标准,建议遵循这些行业内的规范,本文介绍的开源库The Lean Mean C++ Option Parser就可以很好满足我们的需求。
The Lean Mean C++ Option Parser在线文档:(下载头文件和相关demo)The Lean Mean C++ Option Parser: Main Page (sourceforge.net)
一、优点:
1.该库只有一个头文件,只需要包含“#include "optionparser.h"即可”;
2.该库是独立的,没有任何依赖关系,甚至不依赖C或C++标准库;
3.与getopt()和派生函数不同,它不会强制您按顺序循环使用选项,使用更加便捷
二、选项语法:
1.The Lean Mean C++ Option Parser 遵循POSIX getopt()约定,支持GNU风格的getopt_long()长选项以及Perl风格的单减长选项(getopt_long_only());
2.短可选项的格式:-X ,X是任意字符;
3.短可选项的可以组合,比如:-X -Y 和 -XY是一样的;
4.短可选项可以采用单独的或者附加方式取参数,比如:-X foo -Xfoo 。如果注册X为长可选项 ,解析器就可以接受 -X=foo 的格式;
5.最后一个带参数的短可选项可以和其他的组合,比如: -ABCXfoo -ABCX foo (foo 是-X 可选项的参数);
6.长可选项的格式 -可选项名称 ;
7.长可选项格式的可选项名称可以是任意名称,包含任意字符,即使“=”也是可以的,但是不建议这样做;
8.长可选项可以缩写,只要缩写是明确的。此外还可以设置缩写的最小长度;
9.长可选项可以“-”,“--”开始;
10.长可选项可以采用单独的(-option arg)或者附加的(-option=arg)参数格式。附加格式中,必须要使用“=” ;
11.空字符串可以作为附加格式的长可选选项的参数:“-option= ”。作为参数的空字符串和完全没有参数之间的区别需要注意;
12.允许将空字符串作为长可选项和短可选项的单独参数;
13.短可选项和长可选项都可以以“-”字符开头。例如:-X-X, -X -X, -long-X=-X .这三种情况下 的参数都是 -X;
14.如果使用内置的Arg::Optional,则必须附加可选项的参数;
15.特殊选项–(即没有名称)终止选项列表。后面的所有内容都是非选项参数,即使它以“-”字符开头。–本身不会出现在解析结果中;
16.第一个不以“-”开头并且不属于前面的选项的参数将终止选项列表,并且是第一个非选项参数。接下来所有命令行参数都被视为非选项参数,即使它们以“-”开头。
注意:这种行为是由POSIX强制执行的,但GNU getopt()只有在明确请求时(例如通过设置POSIXLY_CORRECT)才会执行。您可以通过将true作为第一个参数传递给例如Parser::parse()来启用GNU行为。
17.看起来像选项(即“-”后面至少有1个字符)但实际上不是的参数不被视为非选项参数。它们被视为未知选项,并被收集到用于错误报告的未知选项列表中。这意味着,为了传递以减号字符开头的第一个非选项参数,需要使用– 特殊选项,例如:
program -x -- --strange-filename
在这个例子中, –strange-filename 是非选项参数。如果前面的‘-’ 没有,它将被视为未知选项。
三、使用:
熟悉以下几个类,即可快速使用该库,下面对这些类型进行介绍:
1.Descriptor
描述一个选项、它的帮助文本(用法)以及应该如何解析它。下面是一个示例:
enum OptionIndex {CREATE, ...};
enum OptionType {DISABLE, ENABLE, OTHER};
const option::Descriptor usage[] = {{ CREATE, // indexOTHER, // type"c", // shortopt"create", // longoptArg::None, // check_arg"--create Tells the program to create something." // help}, ...
};
index:解析器解析后该可选项所在数组的索引。建议使用枚举增强阅读性,如上示例。
描述符具有相同索引的命令行选项将按照它们在命令行上出现的顺序出现在相同的链表中。如果有多个长选项别名引用同一个选项,请为它们的描述符指定相同的索引。
如果你有意思完全相反的选项(例如–enable foo和–disable foo),你也应该给它们相同的索引,但通过不同的类型值来区分它们。这样,它们最终会出现在同一个列表中,你就可以只取列表的最后一个元素并使用其类型。通过这种方式,你可以稍后在命令行上的开关会覆盖以前的开关,而无需手动编码
type:用于区分相同index的可选项。
shortopt:此字符串中的每个字符都将被接受为短选项字符。该字符串不得包含减号字符“-”,否则将出现未定义的行为。如果此描述符不应包含短选项字符,请使用空字符串“”。此处不允许使用NULL!
longopt:长可选项名称。如果此描述符不应具有长选项名称,请使用空字符串“”。此处不允许使用NULL!虽然shortopt允许多个短选项字符,但每个描述符只能有一个长选项名称。如果有多个长选项名称引用同一个选项,请使用具有相同索引和类型的单独描述符。您可以在这样的别名描述符中重复短选项字符,但没有必要这样做。
check_arg:对于每个匹配shortopt或longopt的选项,将调用此函数来检查该选项的潜在参数。
2.Arg
每个选项参数都有一个如此函数设置进Descriptor,用于检查选项参数有效性。
typedef ArgStatus (*CheckArg)(const Option& option, bool msg);
它用于检查选项是否可以接受潜在的参数。即使没有参数,该函数也会被调用。在这种情况下,option.arg将为NULL。
如果msg为true,并且函数确定参数是不可接受的,并且这是一个致命错误,那么它应该在返回ARG_ILEGAL之前向用户输出一条消息。如果msg为false,则该函数应保持静音(否则将收到重复的消息)。
ArgStatus的定义如下:
ARG_NONE | 选项没有参数。 |
ARG_OK | 参数被选项接受。 |
ARG_IGNORE | 该参数是不可接受的,但这不是致命的,因为该选项的参数是可选的。 |
ARG_ILLEGAL | 参数不可以接受,会有致命错误。 |
目前已经预制了几个校验规则,需要更为精准的校验规则可以自己定制,例如:
struct Arg: public option::Arg
{static void printError(const char* msg1, const option::Option& opt, const char* msg2){fprintf(stderr, "ERROR: %s", msg1);fwrite(opt.name, opt.namelen, 1, stderr);fprintf(stderr, "%s", msg2);}static option::ArgStatus Unknown(const option::Option& option, bool msg){if (msg) printError("Unknown option '", option, "'\n");return option::ARG_ILLEGAL;}static option::ArgStatus Required(const option::Option& option, bool msg){if (option.arg != 0)return option::ARG_OK;if (msg) printError("Option '", option, "' requires an argument\n");return option::ARG_ILLEGAL;}static option::ArgStatus NonEmpty(const option::Option& option, bool msg){if (option.arg != 0 && option.arg[0] != 0)return option::ARG_OK;if (msg) printError("Option '", option, "' requires a non-empty argument\n");return option::ARG_ILLEGAL;}static option::ArgStatus Numeric(const option::Option& option, bool msg){char* endptr = 0;if (option.arg != 0 && strtol(option.arg, &endptr, 10)){};if (endptr != option.arg && *endptr == 0)return option::ARG_OK;if (msg) printError("Option '", option, "' requires a numeric argument\n");return option::ARG_ILLEGAL;}
};
3.Stats
确定用于Parser的缓冲区和选项数组的最小长度。因为Parser不使用动态内存,所以必须预先分配其输出数组。如果您不想使用固定大小的数组(可能会变得太小,导致命令行参数被丢弃),可以使用Stats来确定正确的大小。
buffer_max:真实参数个数;
options_max:依赖Descriptor,比Descriptor中的Index数量多一个。
4.Parser
检查参数的有效性,并将其解析为更易于使用的数据结构。
int main(int argc, char* argv[])
{argc-=(argc>0); argv+=(argc>0); // skip program name argv[0] if presentoption::Stats stats(usage, argc, argv);option::Option options[stats.options_max], buffer[stats.buffer_max];option::Parser parse(usage, argc, argv, options, buffer);if (parse.error())return 1;if (options[HELP])...
optionsCount():返回有效选项数量;
nonOptionsCount():返回非选项参数数量;
error():返回是否存在解析错误。选项的非法参数(即CheckArg返回ARG_ILEGAL)是一个不可恢复的错误,会中止解析。只有当CheckArg函数返回ARG_ILEGAL时,未知选项才是错误。否则,它们将被收集。
5.Parser
命令行中已解析的选项及其参数(如果有)。
Parser将具有相同Descriptor::索引的所有已解析选项链接在一起,形成一个链表。这使您能够轻松实现处理重复选项和启用/禁用对的所有常见方法。
desc:指向选项的Descriptor;
name:选项的名称;
arg:选项的参数;
namelen:选项名称长度。
示例:
//Test for presence of a switch in the argument vector:
if ( options[QUIET] ) ...
//Evaluate –enable-foo/–disable-foo pair where the last one used wins:
if ( options[FOO].last()->type() == DISABLE ) ...
//Cumulative option (-v verbose, -vv more verbose, -vvv even more verbose):
int verbosity = options[VERBOSE].count();
//Iterate over all –file=<fname> arguments:
for (Option* opt = options[FILE]; opt; opt = opt->next())fname = opt->arg; ...
四、整体示例:
#include "optionparser.h"
#include <sstream>struct Arg : public option::Arg
{static void print_error(const char* msg1,const option::Option& opt,const char* msg2){fprintf(stderr, "%s", msg1);fwrite(opt.name, opt.namelen, 1, stderr);fprintf(stderr, "%s", msg2);}static option::ArgStatus Unknown(const option::Option& option,bool msg){if (msg){print_error("Unknown option '", option, "'\n");}return option::ARG_ILLEGAL;}static option::ArgStatus Required(const option::Option& option,bool msg){if (option.arg != 0 && option.arg[0] != 0){return option::ARG_OK;}if (msg){print_error("Option '", option, "' requires an argument\n");}return option::ARG_ILLEGAL;}static option::ArgStatus Numeric(const option::Option& option,bool msg){char* endptr = 0;if ( option.arg != nullptr ){strtol(option.arg, &endptr, 10);if (endptr != option.arg && *endptr == 0){return option::ARG_OK;}}if (msg){print_error("Option '", option, "' requires a numeric argument\n");}return option::ARG_ILLEGAL;}template<long min = 0, long max = std::numeric_limits<long>::max()>static option::ArgStatus NumericRange(const option::Option& option,bool msg){static_assert(min <= max, "NumericRange: invalid range provided.");char* endptr = 0;if ( option.arg != nullptr ){long value = strtol(option.arg, &endptr, 10);if ( endptr != option.arg && *endptr == 0 &&value >= min && value <= max){return option::ARG_OK;}}if (msg){std::ostringstream os;os << "' requires a numeric argument in range ["<< min << ", " << max << "]" << std::endl;print_error("Option '", option, os.str().c_str());}return option::ARG_ILLEGAL;}static option::ArgStatus String(const option::Option& option,bool msg){if (option.arg != 0){return option::ARG_OK;}if (msg){print_error("Option '", option, "' requires an argument\n");}return option::ARG_ILLEGAL;}};enum optionIndex
{UNKNOWN_OPT,HELP,SAMPLES,INTERVAL,ENVIRONMENT,
};const option::Descriptor usage[] = {{ UNKNOWN_OPT, 0, "", "", Arg::None,"Usage: HelloWorldExample <publisher|subscriber>\n\nGeneral options:" },{ HELP, 0, "h", "help", Arg::None, " -h \t--help \tProduce help message." },{ UNKNOWN_OPT, 0, "", "", Arg::None, "\nPublisher options:"},{ SAMPLES, 0, "s", "samples", Arg::NumericRange<>," -s <num>, \t--samples=<num> \tNumber of samples (0, default, infinite)." },{ INTERVAL, 0, "i", "interval", Arg::NumericRange<>," -i <num>, \t--interval=<num> \tTime between samples in milliseconds (Default: 100)." },{ ENVIRONMENT, 0, "e", "env", Arg::None, " -e \t--env \tLoad QoS from environment." },{ 0, 0, 0, 0, 0, 0 }
};int main(int argc,char** argv)
{argc -= (argc > 0);argv += (argc > 0); // skip program name argv[0] if presentoption::Stats stats(true, usage, argc, argv);std::vector<option::Option> options(stats.options_max);std::vector<option::Option> buffer(stats.buffer_max);option::Parser parse(true, usage, argc, argv, &options[0], &buffer[0]);try{if (parse.error()){throw 1;}if (options[HELP] || options[UNKNOWN_OPT]){throw 1;}const char* type_name = parse.nonOption(0);if (parse.optionsCount() && type_name >= buffer[0].name){throw 2;}}catch(int error){//deal error}return 0;
}
相关文章:
程序参数解析C/C++库 The Lean Mean C++ Option Parser
开发中我们经常使用程序参数,根据参数的不同来实现不同的功能。POSIX和GNU组织对此都制定了一些标准,为了我们程序更为通用标准,建议遵循这些行业内的规范,本文介绍的开源库The Lean Mean C Option Parser就可以很好满足我们的需求…...

Java中的深拷贝和浅拷贝
目录 🍎引出拷贝 🍎浅拷贝 🍎深拷贝 🍎总结 引出拷贝 现在有一个学生类和书包类,在学生类中有引用类型的书包变量: class SchoolBag {private String brand; //书包的品牌private int size; //书…...

大文件上传
上图就是大致的流程一、标题图片上传课程的标题图片Ajax发送请求到后端后端接收到图片使用IO流去保存图片,返回图片的信息对象JS回调函数接收对象通过$("元素id").val(值),方式给页面form表达img标签src属性值,达到上传图片并回显二…...

Python每日一练(20230327)
目录 1. 最大矩形 🌟🌟🌟 2. 反转链表 II 🌟🌟 3. 单词接龙 II 🌟🌟🌟 🌟 每日一练刷题专栏 🌟 Golang每日一练 专栏 Python每日一练 专栏 C/C每日…...

Centos7 升级内核到5.10mellanox 编译安装
升级5.10内核 #uname -r 重启后 进入新的内核 进入新的内核信息 直接查看是看不到gcc版本 5.10需要高版本gcc 才可以进行编译...

冯诺依曼,操作系统以及进程概念
文章目录一.冯诺依曼体系结构二.操作系统(operator system)三.系统调用和库函数四.进程1.进程控制块(PCB)2.查看进程3.系统相关的调用4.fork介绍(并发引入)五.总结一.冯诺依曼体系结构 计算机大体可以说是…...

7.网络爬虫—正则表达式详讲
7.网络爬虫—正则表达式详讲与实战Python 正则表达式re.match() 函数re.search方法re.match与re.search的区别re.compile 函数检索和替换检索:替换:findallre.finditerre.split正则表达式模式常见的字符类正则模式正则表达式模式量词正则表达式举例前言&…...

关于位运算的巧妙性:小乖,你真的明白吗?
一.位运算的概念什么是位运算?程序中的所有数在计算机内存中都是以二进制的形式储存的。位运算就是直接对整数在内存中的二进制位进行操作。位运算就是直接操作二进制数,那么有哪些种类的位运算呢?常见的运算符有与(&)、或(|)、异或(^)、…...

【Android车载系列】第5章 AOSP开发环境配置
1 硬件支持 建议空闲内存16G以上,同时硬盘400G以上 内存不够可以使用 Linux 的交换分区2 VMware Workstation安装 https://download3.vmware.com/software/wkst/file/VMware-workstation-full-16.1.1-17801498.exe2.1 Ubuntu镜像 http://mirrors.aliyun.com/ubun…...

个人时间管理网站—Git项目管理
🌟所属专栏:献给榕榕🐔作者简介:rchjr——五带信管菜只因一枚😮前言:该专栏系为女友准备的,里面会不定时发一些讨好她的技术作品,感兴趣的小伙伴可以关注一下~👉文章简介…...
2023最新ChatGPT整理的40道Java高级面试题
2023 年最火的就是 ChatGPT 了,很多同事使用他完成一些代码上的智能提示,也有人使用它发了财《「用ChatGPT年入百万!」各博主发布生财之道,网友:答辩搬运工》、《“躺着就能赚大钱”?ChatGPT火了,有人早就动起坏脑筋》等。 最近我也使用 ChatGPT 写技术文章了,比如:《…...

单机分布式一体化是什么?真的是数据库的未来吗,OceanBase或将开启新的里程碑
一. 数据 我们先说说数据这个东西,这段时间的ChatGPT在全世界的爆火说明了一件事,数据是有用的,并且大量的数据如果有一个合适的LLM大规模语言模型训练之后,可以很高程度的完成很多意想不到的事情。 我们大多数的时候的注意力只…...

100天精通Python丨基础知识篇 —— 03、Python基础知识扫盲(第一个Python程序,13个小知识点)
文章目录🐜 1、Python 初体验Pycharm 第一个程序交互式编程第一个程序🐞 2、Python 引号🐔 3、Python 注释🦅 4、Python 保留字符🐯 5、Python 行和缩进🐨 6、Python 空行🐹 7、Python 输出&…...

springboot逍遥大药房管理系统
084-springboot逍遥大药房管理系统演示录像开发语言:Java 框架:springboot JDK版本:JDK1.8 服务器:tomcat7 数据库:mysql 5.7 数据库工具:Navicat11 开发软件:eclipse/myeclipse/idea Maven包&a…...

ZYNQ中的GPIO与AXI GPIO
GPIO GPIO—一种外设,对器件进行观测和控制MIO—将来自PS外设和静态存储器接口的访问多路复用到PS引脚上处理器控制外设的方法—通过一组寄存器包括状态寄存器和控制寄存器,这些寄存器都是有地址的,通过这些寄存器的读写进行外设的控制sessi…...
接口导入功能
1.接口api export function import(param) { return fetch({ url: XXX.import, method: POST, headers: { Content-Type: multipart/form-data; }, data: param }) } 2.页面vue 和 js逻辑 <el-button :loading"disable&qu…...
网络安全知识点总结 期末总结
1、信息安全从总体上可以分成5个层次,密码技术 是信息安全中研究的关键点。 2、握手协议 用于客户机与服务器建立起安全连接之前交换一系列信息的安全信道。 3、仅设立防火墙系统,而没有 安全策略 ,防火墙就形同虚设。 4、应用代理防火墙 …...

linux挂载远程目录
服务端操作 # 1、安装NFS程序 yum -y install nfs* rpcbind,在centos6以前自带的yum源中为portmap。 使用yum安装nfs时会下载依赖,因此只要下载nfs即可,无需再下载rpcbind. # 2、查看是否安装了nfs与rpcbind rpm -qa | grep nfs rpm -qa | grep rpc…...
ChatGPT—初识
ChatGPT初识 由于ChatGPT 注册相关的文章被平台限制了,所以有注册相关的问题可以私聊,或者可以代注册 Chat GPT是一款基于GPT模型的对话型AI模型,能够模拟真实的对话风格和行为方式,让人与AI的交互变得更加自然顺畅。下面将从Chat…...

【ArcGIS Pro二次开发】(18):地理处理工具类【Geoprocessing】补遗
ArcGIS Pro SDK 3.0中的Geoprocessing类是用于执行地理处理工具的核心类。地理处理工具是用于执行空间分析、数据转换、数据管理等任务的工具集,包括常见的空间分析工具、栅格处理工具、矢量处理工具、地图制图工具等。 之前有简单记录了下Geoprocessing工具的用法…...

业务系统对接大模型的基础方案:架构设计与关键步骤
业务系统对接大模型:架构设计与关键步骤 在当今数字化转型的浪潮中,大语言模型(LLM)已成为企业提升业务效率和创新能力的关键技术之一。将大模型集成到业务系统中,不仅可以优化用户体验,还能为业务决策提供…...

css实现圆环展示百分比,根据值动态展示所占比例
代码如下 <view class""><view class"circle-chart"><view v-if"!!num" class"pie-item" :style"{background: conic-gradient(var(--one-color) 0%,#E9E6F1 ${num}%),}"></view><view v-else …...
深入浅出:JavaScript 中的 `window.crypto.getRandomValues()` 方法
深入浅出:JavaScript 中的 window.crypto.getRandomValues() 方法 在现代 Web 开发中,随机数的生成看似简单,却隐藏着许多玄机。无论是生成密码、加密密钥,还是创建安全令牌,随机数的质量直接关系到系统的安全性。Jav…...

Maven 概述、安装、配置、仓库、私服详解
目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...
Webpack性能优化:构建速度与体积优化策略
一、构建速度优化 1、升级Webpack和Node.js 优化效果:Webpack 4比Webpack 3构建时间降低60%-98%。原因: V8引擎优化(for of替代forEach、Map/Set替代Object)。默认使用更快的md4哈希算法。AST直接从Loa…...
【LeetCode】3309. 连接二进制表示可形成的最大数值(递归|回溯|位运算)
LeetCode 3309. 连接二进制表示可形成的最大数值(中等) 题目描述解题思路Java代码 题目描述 题目链接:LeetCode 3309. 连接二进制表示可形成的最大数值(中等) 给你一个长度为 3 的整数数组 nums。 现以某种顺序 连接…...

Ubuntu系统复制(U盘-电脑硬盘)
所需环境 电脑自带硬盘:1块 (1T) U盘1:Ubuntu系统引导盘(用于“U盘2”复制到“电脑自带硬盘”) U盘2:Ubuntu系统盘(1T,用于被复制) !!!建议“电脑…...
pycharm 设置环境出错
pycharm 设置环境出错 pycharm 新建项目,设置虚拟环境,出错 pycharm 出错 Cannot open Local Failed to start [powershell.exe, -NoExit, -ExecutionPolicy, Bypass, -File, C:\Program Files\JetBrains\PyCharm 2024.1.3\plugins\terminal\shell-int…...

ubuntu22.04有线网络无法连接,图标也没了
今天突然无法有线网络无法连接任何设备,并且图标都没了 错误案例 往上一顿搜索,试了很多博客都不行,比如 Ubuntu22.04右上角网络图标消失 最后解决的办法 下载网卡驱动,重新安装 操作步骤 查看自己网卡的型号 lspci | gre…...

Mysql故障排插与环境优化
前置知识点 最上层是一些客户端和连接服务,包含本 sock 通信和大多数jiyukehuduan/服务端工具实现的TCP/IP通信。主要完成一些简介处理、授权认证、及相关的安全方案等。在该层上引入了线程池的概念,为通过安全认证接入的客户端提供线程。同样在该层上可…...