Last active
October 2, 2021 23:30
-
-
Save SealtielFreak/e41893507801357b332ac66cb770f595 to your computer and use it in GitHub Desktop.
Argument Parser
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
nice