命令行参数解析(c++17)

#pragma once

#include <algorithm>
#include <iomanip>
#include <sstream>
#include <iostream>
#include <string>
#include <variant>
#include <vector>

class CommandLine 
{
public:
	// the possible variables the options may point to
	typedef std::variant<uint32_t*, bool*, std::string*> Value;

	struct Argument
	{
		std::vector<std::string> options_;
		Value                    value_;
		std::string              desc_;
	};

public:
	explicit CommandLine() = default;

	// adds a possible option
	void Add(std::vector<std::string> const& opts, Value const& value, std::string const& desc)
	{
		args_.emplace_back( Argument{ opts, value, desc } );
	}

	void PrintHelp(std::ostream& os = std::cout) const
	{
		const auto maxOptionLength = MaxOptionsLength();
	
		for (auto const& arg : args_) 
		{
			std::string opts;
			
			for (auto const& opt : arg.options_)
				opts += opt + ", ";
	
			// Remove last comma and space and add padding for alignment
			std::stringstream sstr;
			sstr << std::left << std::setw(maxOptionLength) << opts.substr(0, opts.size() - 2);
			
			// Print each argument. Do line wrapping for long descriptions.
			size_t spacePos = 0;
			size_t lineWidth = 0;
			
			while (spacePos != std::string::npos) 
			{
				size_t nextspacePos = arg.desc_.find_first_of(' ', spacePos + 1);
				sstr << arg.desc_.substr(spacePos, nextspacePos - spacePos);
				lineWidth += nextspacePos - spacePos;
				spacePos = nextspacePos;
				
				if (lineWidth > 60) 
				{
					os << sstr.str() << std::endl;
					sstr = std::stringstream();
					sstr << std::left << std::setw(maxOptionLength - 1) << " ";
					lineWidth = 0;
				}
			}
		}
	}

	// if an option is set multiple times, the last one will be finally used. 
	// Unknown flags will cause a warning on std::cerr.
	void Parse(int argc, char* argv[]) const
	{
		// Skip the first argument (name of the program).
		int i = 1;
		
		while (i < argc) 
		{
			// First we have to identify whether the value is separated by a space or a '='.
			std::string flag(argv[i]);
			std::string value;
			bool valueIsSeparate = false;

			// If there is an '=' in the flag, the part after the '=' is actually the value.
			size_t equalPos = flag.find('=');
			
			if (equalPos != std::string::npos) 
			{
				value = flag.substr(equalPos + 1);
				flag = flag.substr(0, equalPos);
			}
			else if (i + 1 < argc)  // Else the following argument is the value.
			{
				value = argv[i + 1];
				valueIsSeparate = true;
			}

			// Search for an argument with the provided flag.
			bool foundArgument = false;
			
			for (auto const& argument : args_) 
			{
				if (std::find(argument.options_.begin(), argument.options_.end(), flag) != std::end(argument.options_)) 
				{
					foundArgument = true;

					// In the case of booleans, there must not be a value present
					if (std::holds_alternative<bool*>(argument.value_)) 
					{
						if (!value.empty() && value != "true" && value != "false") 
						{
							valueIsSeparate = false;
						}

						*std::get<bool*>(argument.value_) = (value != "false");
					}
					// In all other cases there must be a value.
					else if (value.empty()) 
					{
						throw std::runtime_error("Failed to parse command line arguments: Missing value for argument \"" + flag + "\"!");
					}
					// For a std::string, we take the entire value.
					else if (std::holds_alternative<std::string*>(argument.value_)) 
					{
						*std::get<std::string*>(argument.value_) = value;
					}
					// In all other cases we use a std::stringstream to convert the value.
					else  
					{
						std::visit([&value](auto&& arg) {
						  std::stringstream sstr(value);
						  sstr >> *arg; 
						}, argument.value_);
					}

					break;
				}
			}

			// Print a warning if there was an unknown argument.
			if (!foundArgument)
				std::cerr << "Ignoring unknown command line argument \"" << flag << "\"." << std::endl;

			// Advance to the next flag.
			++i;

			// If the value was separated, we have to advance our index once more.
			if (foundArgument && valueIsSeparate)
				++i;
		}
	}

private:
	// for alignment : Find the argument with the longest combined option length
	uint32_t MaxOptionsLength(void) const
	{
		constexpr auto COMMA_LENGTH = 1U;
		constexpr auto SPACE_LENTH = 1U;
		uint32_t max_len = 0;

		for (auto const& arg : args_)
		{
			uint32_t len = 0;

			for (auto const& opt : arg.options_)
			{
				len += static_cast<uint32_t>(opt.size()) + COMMA_LENGTH + SPACE_LENTH;
			}

			max_len = std::max(max_len, len);
		}

		return max_len;
	}

 private:
	std::vector<Argument> args_;

使用



public:
	void Test(int argc, char* argv[]) const
	{
		std::string usr = "";
		std::string pwd = "";
		std::string code = "";
		
		bool do_auth = false;
		bool print_help = false;

		CommandLine args;
		args.Add({ "-u", "--user" },			&usr, "<apple ID>");
		args.Add({ "-p", "--password" },		&pwd, "<password>");
		args.Add({ "-c", "--code" },			&code, "security code");
		args.Add({ "-a", "--auth" },			&do_auth, "authenticate");
		args.Add({ "-h", "--help" },			&print_help, "Help");

		try
		{
			args.Parse(argc, argv);
		}
		catch (std::runtime_error const& e)
		{
			std::cout << e.what() << std::endl;
			return;
		}

		if (print_help)
		{
			args.PrintHelp();
			return;
		}

		std::cout
			<< "usr : " << usr << std::endl
			<< "pwd : " << pwd << std::endl
			<< "code : " << code << std::endl
			<< "auth: " << do_auth << std::endl
			<< "print help : " << print_help << std::endl;
	}
};
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要在C++中使用Boost库进行命令行参数解析,您需要使用Boost.Program_options模块。以下是一个示例: ```cpp #include <iostream> #include <boost/program_options.hpp> namespace po = boost::program_options; int main(int argc, char** argv) { po::options_description desc("Allowed options"); desc.add_options() ("help", "显示帮助信息") ("input", po::value<std::string>(), "输入文件名") ("output", po::value<std::string>(), "输出文件名"); po::variables_map vm; po::store(po::parse_command_line(argc, argv, desc), vm); po::notify(vm); if (vm.count("help")) { std::cout << desc << std::endl; return 0; } if (vm.count("input")) { std::string inputFileName = vm["input"].as<std::string>(); std::cout << "输入文件名: " << inputFileName << std::endl; } if (vm.count("output")) { std::string outputFileName = vm["output"].as<std::string>(); std::cout << "输出文件名: " << outputFileName << std::endl; } return 0; } ``` 在这个示例中,我们使用`boost::program_options`命名空间来定义命令行选项。`desc`对象包含了可以接受的选项,比如`--help`、`--input`和`--output`。每个选项都可以接受一个参数。 然后,我们使用`po::parse_command_line`函数来解析命令行参数,并将解析结果存储在`vm`(variables_map)对象中。`po::notify`函数用于通知`variables_map`对象已经完成解析。 接下来,我们可以通过检查`variables_map`对象中的选项是否存在来处理用户提供的命令行参数。在示例中,我们检查`--help`、`--input`和`--output`选项是否存在,并使用`as<std::string>()`方法获取选项的值。 如果用户提供了`--help`选项,我们将打印出命令行选项的帮助信息。否则,我们将打印出输入文件名和输出文件名(如果有提供的话)。 请确保在编译时链接了Boost.Program_options库,并将编译器的标志设置为`-lboost_program_options`。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值