2#include "fmt/color.hpp"
24inline std::string
fstring(
const std::string format, ...) {
25 constexpr std::size_t size = 256;
27 fmt_str.resize(size + 1);
33 va_start(args, format);
34 vsnprintf(&fmt_str[0], fmt_str.size(), format.c_str(), args);
38 fmt_str.erase(std::find(fmt_str.begin(), fmt_str.end(),
'\0'), fmt_str.end());
44inline std::string
fstring(
const std::size_t size,
const std::string format,
49 fmt_str.resize(size + 1);
55 va_start(args, format);
56 vsnprintf(&fmt_str[0], fmt_str.size(), format.c_str(), args);
60 fmt_str.erase(std::find(fmt_str.begin(), fmt_str.end(),
'\0'), fmt_str.end());
73 const auto wc = std::find(s2.cbegin(), s2.cend(),
'*');
77 const auto pos_wc = std::size_t(std::distance(s2.cbegin(), wc));
79 const auto s1_front = s1.substr(0, pos_wc);
80 const auto s2_front = s2.substr(0, pos_wc);
83 const auto len_back = std::size_t(std::distance(wc + 1, s2.cend()));
85 const auto pos_1_back = s1.length() > len_back ? s1.length() - len_back : 0;
86 const auto s1_back = s1.substr(pos_1_back, std::string::npos);
87 const auto s2_back = s2.substr(pos_wc + 1, std::string::npos);
89 return s1_front == s2_front && s1_back == s2_back;
97 return static_cast<char>(std::tolower(
static_cast<unsigned char>(ch)));
101inline std::string
tolower(std::string t_string) {
102 for (
auto &c : t_string) {
111inline bool contains(std::string_view the_string, std::string_view sub_string) {
112 return the_string.find(sub_string) != std::string::npos;
117 const std::string &sub_string) {
118 return tolower(the_string).find(
tolower(sub_string)) != std::string::npos;
123 const std::vector<std::string> &sub_strings) {
124 for (
const auto &substr : sub_strings) {
133 const std::vector<std::string> &sub_strings) {
134 for (
const auto &substr : sub_strings) {
144inline bool ci_compare(std::string_view s1, std::string_view s2) {
146 s1.cbegin(), s1.cend(), s2.cbegin(), s2.cend(),
147 [](
char c1,
char c2) { return qip::tolower(c1) == qip::tolower(c2); });
158 const auto wc = std::find(s2.cbegin(), s2.cend(),
'*');
162 const auto pos_wc = std::size_t(std::distance(s2.cbegin(), wc));
164 const auto s1_front = s1.substr(0, pos_wc);
165 const auto s2_front = s2.substr(0, pos_wc);
168 const auto len_back = std::size_t(std::distance(wc + 1, s2.cend()));
170 const auto pos_1_back = s1.length() > len_back ? s1.length() - len_back : 0;
171 const auto s1_back = s1.substr(pos_1_back, std::string::npos);
172 const auto s2_back = s2.substr(pos_wc + 1, std::string::npos);
180inline auto Levenstein(std::string_view a, std::string_view b) {
183 std::vector<size_t> d_t((a.size() + 1) * (b.size() + 1),
size_t(-1));
184 auto d = [&](
size_t ia,
size_t ib) ->
size_t & {
185 return d_t[ia * (b.size() + 1) + ib];
187 std::function<size_t(
size_t,
size_t)> LevensteinInt =
188 [&](
size_t ia,
size_t ib) ->
size_t {
189 if (d(ia, ib) != size_t(-1))
193 dist = a.size() - ia;
194 else if (ia >= a.size())
195 dist = b.size() - ib;
196 else if (a[ia] == b[ib])
197 dist = LevensteinInt(ia + 1, ib + 1);
199 dist = 1 + std::min(std::min(LevensteinInt(ia, ib + 1),
200 LevensteinInt(ia + 1, ib)),
201 LevensteinInt(ia + 1, ib + 1));
205 return LevensteinInt(0, 0);
210 std::vector<size_t> d_t((a.size() + 1) * (b.size() + 1),
size_t(-1));
211 auto d = [&](
size_t ia,
size_t ib) ->
size_t & {
212 return d_t[ia * (b.size() + 1) + ib];
214 std::function<size_t(
size_t,
size_t)> LevensteinInt =
215 [&](
size_t ia,
size_t ib) ->
size_t {
216 if (d(ia, ib) != size_t(-1))
220 dist = a.size() - ia;
221 else if (ia >= a.size())
222 dist = b.size() - ib;
224 dist = LevensteinInt(ia + 1, ib + 1);
226 dist = 1 + std::min(std::min(LevensteinInt(ia, ib + 1),
227 LevensteinInt(ia + 1, ib)),
228 LevensteinInt(ia + 1, ib + 1));
232 return LevensteinInt(0, 0);
238 const std::vector<std::string> &list) {
239 auto compare = [&test_string](
const auto &s1,
const auto &s2) {
242 return std::min_element(list.cbegin(), list.cend(),
compare);
248 const std::vector<std::string> &list) {
249 auto compare = [&test_string](
const auto &s1,
const auto &s2) {
253 using namespace std::string_literals;
254 return list.empty() ?
""s :
255 *std::min_element(list.cbegin(), list.cend(),
compare);
270 std::find_if(s.cbegin() + 1, s.cend(),
271 [](
auto c) { return !std::isdigit(c); }) == s.end() &&
273 (std::isdigit(s[0]) || ((s[0] ==
'-' || s[0] ==
'+') && s.size() > 1));
279inline std::vector<std::string>
split(
const std::string &s,
char delim =
' ') {
280 std::vector<std::string> out;
281 std::stringstream ss(s);
283 while (getline(ss, tmp, delim)) {
290inline std::string
concat(
const std::vector<std::string> &v,
291 const std::string &delim =
"") {
293 for (std::size_t i = 0; i < v.size(); ++i) {
295 if (i != v.size() - 1)
308inline std::string
wrap(
const std::string &input, std::size_t at = 80,
309 const std::string &prefix =
"") {
311 const auto length = at - prefix.size();
312 std::size_t ipos = 0;
313 std::size_t fpos = length;
314 while (ipos < input.length()) {
318 auto temp_pos_nl = input.find(
'\n', ipos);
319 if (temp_pos_nl > ipos && temp_pos_nl < fpos &&
320 temp_pos_nl != std::string::npos) {
321 output += prefix + input.substr(ipos, temp_pos_nl - ipos);
322 ipos = temp_pos_nl + 1;
323 fpos = ipos + length;
327 if (fpos >= input.length()) {
328 output += prefix + input.substr(ipos, fpos - ipos);
332 auto temp_pos = input.rfind(
' ', fpos);
333 if (temp_pos <= ipos || temp_pos == std::string::npos) {
334 output += prefix + input.substr(ipos, fpos - ipos);
336 fpos = ipos + length;
338 output += prefix + input.substr(ipos, temp_pos - ipos);
340 fpos = ipos + length;
353 return std::to_string(a);
354 static const std::string M[] = {
"",
"M",
"MM",
"MMM"};
355 static const std::string C[] = {
"",
"C",
"CC",
"CCC",
"CD",
356 "D",
"DC",
"DCC",
"DCCC",
"CM"};
357 static const std::string X[] = {
"",
"X",
"XX",
"XXX",
"XL",
358 "L",
"LX",
"LXX",
"LXXX",
"XC"};
359 static const std::string I[] = {
"",
"I",
"II",
"III",
"IV",
360 "V",
"VI",
"VII",
"VIII",
"IX"};
361 return M[a / 1000] + C[(a % 1000) / 100] + X[(a % 100) / 10] + I[(a % 10)];
367inline std::uint64_t
hash(std::string_view
string) {
368 std::uint64_t h = 14695981039346656037ull;
369 for (
const auto c : string) {
370 h = (h ^
static_cast<unsigned char>(c)) * 1099511628211ull;
386 std::size_t n_chars = 6) {
387 static const std::string digits =
"0123456789abcdefghijklmnopqrstuvwxyz";
388 auto h =
hash(
string);
389 std::string out(n_chars,
'0');
390 for (std::size_t i = n_chars; i > 0; --i) {
391 out.at(i - 1) = digits.at(h % 36);
General-purpose utility library.
Definition Array.hpp:23
std::uint64_t hash(std::string_view string)
64-bit FNV-1a hash of a string.
Definition String.hpp:367
auto closest_match(std::string_view test_string, const std::vector< std::string > &list)
Returns an iterator to the closest match to test_string in list, using Levenstein distance.
Definition String.hpp:237
std::string concat(const std::vector< std::string > &v, const std::string &delim="")
Concatenates a vector of strings into one, with an optional delimiter.
Definition String.hpp:290
auto Levenstein(std::string_view a, std::string_view b)
Returns the Levenshtein edit distance between strings a and b.
Definition String.hpp:180
std::string ci_closest_match(const std::string_view test_string, const std::vector< std::string > &list)
Returns the closest match (case insensitive) to test_string in list, using ci_Levenstein distance.
Definition String.hpp:247
bool string_is_integer(std::string_view s)
Returns true if the string represents an integer.
Definition String.hpp:267
std::string hash_string(std::string_view string, std::size_t n_chars=6)
Short base-36 (0-9, a-z) form of hash; intended for filenames.
Definition String.hpp:385
std::vector< std::string > split(const std::string &s, char delim=' ')
Splits a string by delimiter into a vector of substrings.
Definition String.hpp:279
bool ci_contains(const std::string &the_string, const std::string &sub_string)
Returns true if the_string contains sub_string (case insensitive).
Definition String.hpp:116
auto ci_Levenstein(std::string_view a, std::string_view b)
Case-insensitive version of Levenstein.
Definition String.hpp:209
bool ci_wc_compare(std::string_view s1, std::string_view s2)
Case-insensitive version of wildcard_compare.
Definition String.hpp:156
std::string int_to_roman(int a)
Converts an integer to a Roman numeral string. Assumes |a| <= 3999.
Definition String.hpp:349
std::string fstring(const std::string format,...)
Returns a formatted string using printf-style format specifiers.
Definition String.hpp:24
bool ci_compare(std::string_view s1, std::string_view s2)
Case-insensitive string comparison; equivalent to tolower(s1) == tolower(s2).
Definition String.hpp:144
bool wildcard_compare(std::string_view s1, std::string_view s2)
Compares s1 against pattern s2, where s2 may contain one wildcard '*' that matches any substring.
Definition String.hpp:71
bool contains(std::string_view the_string, std::string_view sub_string)
Returns true if the_string contains sub_string.
Definition String.hpp:111
auto compare(const std::vector< T > &first, const std::vector< T > &second)
Compares two arithmetic vectors element-wise; returns {max_delta, iterator}.
Definition Vector.hpp:41
std::string wrap(const std::string &input, std::size_t at=80, const std::string &prefix="")
Word-wraps input at column at, optionally prefixing each line.
Definition String.hpp:308
char tolower(char ch)
Conversion of a single character to lowercase.
Definition String.hpp:95