Skip to content

Instantly share code, notes, and snippets.

@SealtielFreak
Last active October 2, 2021 23:30
Show Gist options
  • Save SealtielFreak/e41893507801357b332ac66cb770f595 to your computer and use it in GitHub Desktop.
Save SealtielFreak/e41893507801357b332ac66cb770f595 to your computer and use it in GitHub Desktop.
Argument Parser
#include <iostream>
#include <istream>
#include <regex>
#include <string>
#include <vector>
#include <map>
#include <algorithm>
const auto args = "register --name Diego Sealtiel Valderrama Garcia --age 21 -m --software-engineer AFF8310274";
const std::vector<std::string> except_flags = {"--software-engineer", "-m"};
const std::regex rule_regex(R"(--(\w+-\w+)+|--\w+|-\w)");
struct Arguments {
public:
virtual ~Arguments() {
positional.clear();
optional.clear();
flag.clear();
}
public:
std::vector<std::string> positional;
std::vector<std::string> optional;
std::map<std::string, std::vector<std::string>> flag;
};
template<class Container = std::vector<std::string>>
auto tokenizer(const std::string &str, const char delim = ' ') {
Container tokens;
std::istringstream stream(str);
std::string token;
while (std::getline(stream, token, delim)) {
if (!token.empty()) {
tokens.push_back(token);
}
}
return tokens;
}
template<class Container = std::vector<std::string>>
auto parser(const Container &tokens, const Container except_flags = {}) {
std::map<std::string, std::vector<std::string>> token_map;
std::string argument;
std::size_t position = 0;
for (const auto &token: tokens) {
bool is_flag = false;
bool is_option = false;
// std::find(except_flags.begin(), except_flags.end(), token) != except_flags.end()
if (is_option = std::regex_match(token, rule_regex); is_option) {
argument = token;
}
if(is_flag = std::find(except_flags.begin(), except_flags.end(), argument) != except_flags.end(); is_flag) {
}
if (token_map.find(argument) != token_map.end() and not is_flag) {
token_map.at(argument).push_back(token);
} else {
std::pair<std::string, std::vector<std::string>> element;
if (is_option) {
element.first = token;
element.second = {};
} else {
element.first = std::to_string(position);
element.second = {
token
};
position++;
}
token_map.insert(element);
}
}
return token_map;
}
template<class Container = std::map<std::string, std::vector<std::string>>>
auto eval(const Container &tokens_map) {
Arguments arguments;
for (const auto &[key, value]: tokens_map) {
if (std::regex_match(key, rule_regex)) {
std::pair<std::string, std::vector<std::string>> element;
if (value.empty()) {
arguments.optional.push_back(key);
} else {
element.first = key;
element.second = value;
arguments.flag.insert(element);
}
} else {
try {
std::stoi(key);
for (const auto &v: value) {
arguments.positional.push_back(v);
}
} catch (const std::invalid_argument &e) {
std::cout << e.what() << std::endl;
}
}
}
return arguments;
}
int main() {
/* tokenizer & parsing argument */
auto tokens = tokenizer(args);
auto token_map = parser(tokens, except_flags);
/* eval tokens */
auto arguments = eval(token_map);
/* evaluate tokens */
std::cout << "Positional arguments: " << std::endl;
for (auto i = 0u; i < arguments.positional.size(); i++) {
std::cout << "[" << i << "]: " << arguments.positional[i] << std::endl;
}
std::cout << "Optional arguments: " << std::endl;
for (const auto &arg: arguments.optional) {
std::cout << "[" << arg << "]" << std::endl;
}
std::cout << "Flag arguments: " << std::endl;
for (const auto &[key, values]: arguments.flag) {
std::cout << "[" << key << "]: ";
for (const auto &v: values) {
std::cout << v << " ";
}
std::cout << std::endl;
}
return 0;
}
@yisus44
Copy link

yisus44 commented Oct 2, 2021

nice

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment