Skip to content

Instantly share code, notes, and snippets.

@mrexodia mrexodia/regexmagic.h

Last active Jul 1, 2020
Embed
What would you like to do?
// License: public domain/CC0
#include <regex>
#include <string>
#include <cstdio>
#include <utility>
#include <climits>
#include <cinttypes>
bool parseNumber(const char* str, uint64_t& result, int radix = 0)
{
errno = 0;
char* end;
result = strtoull(str, &end, radix);
if(!result && end == str)
return false;
if(result == ULLONG_MAX && errno)
return false;
if(*end)
return false;
return true;
}
template<typename T, size_t Radix>
struct Number
{
Number(T& value) : value(value) { }
Number(const Number&) = delete;
Number(Number&&) = delete;
private:
T& value;
template<typename>
friend struct Parser;
};
template<typename T>
using Hex = Number<T, 16>;
template<typename T>
struct Parser;
template<>
struct Parser<uint64_t>
{
void parse(const std::string& str, uint64_t& value)
{
if(!parseNumber(str.c_str(), value))
throw std::invalid_argument("Failed to parse '" + str + "' to uint64_t");
}
};
template<>
struct Parser<std::string>
{
void parse(const std::string& str, std::string& value)
{
value = str;
}
};
template<typename T, size_t Radix>
struct Parser<Number<T, Radix>>
{
void parse(const std::string& str, Number<T, Radix>& value)
{
if(!parseNumber(str.c_str(), value.value, Radix))
throw std::invalid_argument("Failed to parse '" + str + "' to Number");
}
};
namespace detail
{
template<typename... Ts>
void discard(Ts...) { }
template<typename T>
bool extract(const std::string& str, T& value)
{
Parser<T>().parse(str, value);
return true;
}
template<typename... Ts, size_t... I>
void extract_smatch_helper(const std::smatch& m, std::tuple<Ts&...> args, std::index_sequence<I...>)
{
discard(extract(m[I + 1].str(), std::get<I>(args))...);
}
template<typename... Ts>
void extract_smatch(const std::smatch& m, Ts&... args)
{
if(sizeof...(args) + 1 != m.size())
throw std::invalid_argument("Amount of capture groups not equal to amount of template parameters");
extract_smatch_helper(m, std::forward_as_tuple(args...), std::index_sequence_for<Ts...>{});
}
}
template<typename... Ts>
bool match(const std::regex& regex, const std::string& str, Ts&... args)
{
std::smatch m;
if(!std::regex_search(str, m, regex))
return false;
detail::extract_smatch(m, args...);
return true;
}
int main()
{
std::string line = "[Debug]: 123: Some text with spaces 0x12345 aff (more text)";
std::smatch m;
std::regex r(R"(^.+]: (\d+): .+(0x[^ ]+) ([0-9a-f]+) .+$)");
uint64_t x, y, z;
Hex<uint64_t> rz(z);
if(match(r, line, x, y, rz))
{
printf("matched: %" PRIu64 ", 0x%" PRIx64 " 0x%" PRIx64 "\n", x, y, z);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.