2020-02-04 07:50:34 +00:00
|
|
|
#pragma once
|
2020-07-06 17:31:40 +00:00
|
|
|
#ifndef MANGOHUD_STRING_UTILS_H
|
|
|
|
#define MANGOHUD_STRING_UTILS_H
|
|
|
|
|
2020-02-04 07:50:34 +00:00
|
|
|
#include <string>
|
2020-11-27 17:59:11 +00:00
|
|
|
#include <vector>
|
2020-02-04 07:50:34 +00:00
|
|
|
#include <iomanip>
|
|
|
|
#include <iostream>
|
|
|
|
#include <sstream>
|
|
|
|
#include <algorithm>
|
|
|
|
#include <cctype>
|
|
|
|
#include <locale>
|
2023-11-22 16:24:20 +00:00
|
|
|
#include <cstring>
|
2020-02-04 07:50:34 +00:00
|
|
|
|
|
|
|
#pragma GCC diagnostic push
|
|
|
|
#pragma GCC diagnostic ignored "-Wunused-function"
|
|
|
|
|
|
|
|
// https://stackoverflow.com/questions/216823/whats-the-best-way-to-trim-stdstring#217605
|
|
|
|
// trim from start (in place)
|
|
|
|
static inline void ltrim(std::string &s) {
|
|
|
|
s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](int ch) {
|
|
|
|
return !std::isspace(ch);
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
|
|
|
|
// trim from end (in place)
|
|
|
|
static inline void rtrim(std::string &s) {
|
|
|
|
s.erase(std::find_if(s.rbegin(), s.rend(), [](int ch) {
|
|
|
|
return !std::isspace(ch);
|
|
|
|
}).base(), s.end());
|
|
|
|
}
|
|
|
|
|
|
|
|
// trim from both ends (in place)
|
|
|
|
static inline void trim(std::string &s) {
|
|
|
|
ltrim(s);
|
|
|
|
rtrim(s);
|
|
|
|
}
|
|
|
|
|
|
|
|
// trim from start (copying)
|
|
|
|
static inline std::string ltrim_copy(std::string s) {
|
|
|
|
ltrim(s);
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
// trim from end (copying)
|
|
|
|
static inline std::string rtrim_copy(std::string s) {
|
|
|
|
rtrim(s);
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
// trim from both ends (copying)
|
|
|
|
static inline std::string trim_copy(std::string s) {
|
|
|
|
trim(s);
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool starts_with(const std::string& s, const char *t) {
|
|
|
|
return s.rfind(t, 0) == 0;
|
|
|
|
}
|
|
|
|
|
2020-03-15 11:09:51 +00:00
|
|
|
static bool ends_with(const std::string& s, const char *t, bool icase = false) {
|
|
|
|
std::string s0(s);
|
|
|
|
std::string s1(t);
|
|
|
|
|
|
|
|
if (s0.size() < s1.size())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (icase) {
|
|
|
|
std::transform(s0.begin(), s0.end(), s0.begin(), ::tolower);
|
|
|
|
std::transform(s1.begin(), s1.end(), s1.begin(), ::tolower);
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t pos = s0.size() - s1.size();
|
|
|
|
return (s0.rfind(s1, pos) == pos);
|
|
|
|
}
|
|
|
|
|
2020-02-04 07:50:34 +00:00
|
|
|
template<typename T>
|
|
|
|
static std::string itox(T i) {
|
|
|
|
std::stringstream ss;
|
|
|
|
ss << "0x"
|
|
|
|
<< std::setfill ('0') << std::setw(sizeof(T) * 2)
|
|
|
|
<< std::hex << i;
|
|
|
|
return ss.str();
|
|
|
|
}
|
|
|
|
|
2020-06-18 21:41:07 +00:00
|
|
|
static bool try_stoi(int& val, const std::string& str)
|
2020-02-04 07:50:34 +00:00
|
|
|
{
|
2020-06-18 21:41:07 +00:00
|
|
|
if (sscanf(str.c_str(), "%d", &val) == 1)
|
2020-02-04 07:50:34 +00:00
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-06-18 21:41:07 +00:00
|
|
|
static bool try_stoull(unsigned long long& val, const std::string& str)
|
2020-02-16 00:52:14 +00:00
|
|
|
{
|
2020-06-18 21:41:07 +00:00
|
|
|
if (sscanf(str.c_str(), "%llu", &val) == 1)
|
2020-02-16 00:52:14 +00:00
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-06-19 01:36:55 +00:00
|
|
|
static float parse_float(const std::string& s, std::size_t* float_len = nullptr){
|
2020-06-19 10:07:16 +00:00
|
|
|
std::stringstream ss(s);
|
2020-06-19 11:44:25 +00:00
|
|
|
ss.imbue(std::locale::classic());
|
2020-06-19 10:07:16 +00:00
|
|
|
float ret;
|
|
|
|
ss >> ret;
|
|
|
|
if(ss.fail()) throw std::invalid_argument("parse_float: Not a float");
|
|
|
|
if(float_len != nullptr){
|
|
|
|
auto pos = ss.tellg();
|
|
|
|
if(ss.fail()) *float_len = s.size();
|
|
|
|
else *float_len = pos;
|
2020-06-19 01:36:55 +00:00
|
|
|
}
|
2020-06-19 10:07:16 +00:00
|
|
|
return ret;
|
2020-06-19 01:36:55 +00:00
|
|
|
}
|
|
|
|
|
2021-09-09 17:52:52 +00:00
|
|
|
static std::vector<std::string> str_tokenize(const std::string& s, const std::string& delims = ",:+")
|
2020-11-27 17:59:11 +00:00
|
|
|
{
|
|
|
|
std::vector<std::string> v;
|
|
|
|
size_t old_n = 0, new_n = 0;
|
|
|
|
|
|
|
|
while (old_n < s.size()){
|
|
|
|
new_n = s.find_first_of(delims, old_n);
|
|
|
|
auto c = s.substr(old_n, new_n - old_n);
|
|
|
|
if (old_n != new_n)
|
|
|
|
v.push_back(c);
|
|
|
|
if (new_n == std::string::npos)
|
|
|
|
break;
|
|
|
|
old_n = new_n + 1;
|
|
|
|
}
|
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
2023-11-22 16:24:20 +00:00
|
|
|
static void trim_char(char* str) {
|
|
|
|
if(!str)
|
|
|
|
return;
|
|
|
|
|
|
|
|
char* ptr = str;
|
|
|
|
int len = strlen(ptr);
|
|
|
|
|
|
|
|
while(len-1 > 0 && isspace(ptr[len-1]))
|
|
|
|
ptr[--len] = 0;
|
|
|
|
|
|
|
|
while(*ptr && isspace(*ptr))
|
|
|
|
++ptr, --len;
|
|
|
|
|
|
|
|
memmove(str, ptr, len + 1);
|
|
|
|
}
|
|
|
|
|
2020-02-04 07:50:34 +00:00
|
|
|
#pragma GCC diagnostic pop
|
2020-07-06 17:31:40 +00:00
|
|
|
|
|
|
|
#endif //MANGOHUD_STRING_UTILS_H
|