SourcePP
Several modern C++20 libraries for sanely parsing Valve's formats.
Loading...
Searching...
No Matches
String.cpp
Go to the documentation of this file.
1#include <sourcepp/String.h>
2
3#include <algorithm>
4#include <cctype>
5#include <format>
6#include <random>
7#include <sstream>
8
9namespace {
10
11std::mt19937& getRandomGenerator() {
12 static std::random_device random_device{};
13 static std::mt19937 generator{random_device()};
14 return generator;
15}
16
17} // namespace
18
19using namespace sourcepp;
20
21bool string::contains(std::string_view s, char c) {
22 return std::find(s.begin(), s.end(), c) != s.end();
23}
24
25bool string::matches(std::string_view in, std::string_view search) {
26 int inPos = 0, searchPos = 0;
27 for ( ; inPos < in.length() && searchPos < search.length(); inPos++, searchPos++) {
28 if (search[searchPos] == '%') {
29 if (++searchPos == search.length()) {
30 return false;
31 }
32 switch (search[searchPos]) {
33 default:
34 case '?': // wildcard
35 break;
36 case 'w': // whitespace
37 if (!std::isspace(in[inPos])) return false;
38 break;
39 case 'a': // letter
40 if (!(in[inPos] >= 'a' && in[inPos] <= 'z' || in[inPos] >= 'A' && in[inPos] <= 'Z')) return false;
41 break;
42 case 'u': // uppercase letter
43 if (!(in[inPos] >= 'A' && in[inPos] <= 'Z')) return false;
44 break;
45 case 'l': // lowercase letter
46 if (!(in[inPos] >= 'a' && in[inPos] <= 'z')) return false;
47 break;
48 case 'd': // digit
49 if (!std::isdigit(in[inPos])) return false;
50 break;
51 case '%': // escaped percent
52 if (in[inPos] != '%') return false;
53 break;
54 }
55 } else if (in[inPos] != search[searchPos]) {
56 return false;
57 }
58 }
59 return inPos == in.length() && searchPos == search.length();
60}
61
62bool string::iequals(std::string_view s1, std::string_view s2) {
63 return std::ranges::equal(s1, s2, [](char a, char b) { return std::tolower(a) == std::tolower(b); });
64}
65
66// https://stackoverflow.com/a/217605
67
68void string::ltrim(std::string& s) {
69 s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](char c) { return !std::isspace(c); }));
70}
71
72std::string_view string::ltrim(std::string_view s) {
73 while (!s.empty() && std::isspace(s[0])) {
74 s.remove_prefix(1);
75 }
76 return s;
77}
78
79void string::rtrim(std::string& s) {
80 s.erase(std::find_if(s.rbegin(), s.rend(), [](char c) { return !std::isspace(c); }).base(), s.end());
81}
82
83std::string_view string::rtrim(std::string_view s) {
84 while (!s.empty() && std::isspace(s[s.size() - 1])) {
85 s.remove_suffix(1);
86 }
87 return s;
88}
89
90void string::trim(std::string& s) {
91 rtrim(s);
92 ltrim(s);
93}
94
95std::string_view string::trim(std::string_view s) {
96 return ltrim(rtrim(s));
97}
98
99void string::trimInternal(std::string& s) {
100 s.erase(std::ranges::unique(s, [](char lhs, char rhs) { return lhs == rhs && std::isspace(lhs); }).begin(), s.end());
101}
102
103std::string string::trimInternal(std::string_view s) {
104 std::string out{s};
105 trimInternal(out);
106 return out;
107}
108
109void string::ltrim(std::string& s, std::string_view chars) {
110 s.erase(s.begin(), std::find_if(s.begin(), s.end(), [chars](char c) {
111 return !contains(chars, c);
112 }));
113}
114
115std::string_view string::ltrim(std::string_view s, std::string_view chars) {
116 while (!s.empty() && contains(chars, s[0])) {
117 s.remove_prefix(1);
118 }
119 return s;
120}
121
122void string::rtrim(std::string& s, std::string_view chars) {
123 s.erase(std::find_if(s.rbegin(), s.rend(), [chars](char c) {
124 return !contains(chars, c);
125 }).base(), s.end());
126}
127
128std::string_view string::rtrim(std::string_view s, std::string_view chars) {
129 while (!s.empty() && contains(chars, s[s.size() - 1])) {
130 s.remove_suffix(1);
131 }
132 return s;
133}
134
135void string::trim(std::string& s, std::string_view chars) {
136 rtrim(s, chars);
137 ltrim(s, chars);
138}
139
140std::string_view string::trim(std::string_view s, std::string_view chars) {
141 return ltrim(rtrim(s, chars), chars);
142}
143
144void string::trimInternal(std::string& s, std::string_view chars) {
145 s.erase(std::ranges::unique(s, [chars](char lhs, char rhs) { return lhs == rhs && std::ranges::find(chars, lhs) != chars.end(); }).begin(), s.end());
146}
147
148std::string string::trimInternal(std::string_view s, std::string_view chars) {
149 std::string out{s};
150 trimInternal(out, chars);
151 return out;
152}
153
154// https://stackoverflow.com/a/46931770
155
156std::vector<std::string> string::split(std::string_view s, char delim) {
157 std::vector<std::string> result;
158 std::stringstream ss(std::string{s});
159 std::string item;
160 while (std::getline(ss, item, delim)) {
161 result.push_back(item);
162 }
163 return result;
164}
165
166void string::toLower(std::string& input) {
167 std::transform(input.begin(), input.end(), input.begin(), [](unsigned char c){ return std::tolower(c); });
168}
169
170std::string string::toLower(std::string_view input) {
171 std::string out{input};
172 toLower(out);
173 return out;
174}
175
176void string::toUpper(std::string& input) {
177 std::transform(input.begin(), input.end(), input.begin(), [](unsigned char c){ return std::toupper(c); });
178}
179
180std::string string::toUpper(std::string_view input) {
181 std::string out{input};
182 toUpper(out);
183 return out;
184}
185
186std::string string::createRandom(uint16_t length, std::string_view chars) {
187 auto& generator = ::getRandomGenerator();
188 std::uniform_int_distribution distribution{0, static_cast<int>(chars.length() - 1)};
189
190 std::string out;
191 for (uint16_t i = 0; i < length; i++) {
192 out += chars[distribution(generator)];
193 }
194
195 return out;
196}
197
199 static constexpr std::string_view chars = "0123456789abcdef";
200
201 auto& generator = ::getRandomGenerator();
202 std::uniform_int_distribution distribution{0, static_cast<int>(chars.length() - 1)};
203
204 std::string out;
205 for (uint16_t i = 0; i < 8; i++) {
206 out += chars[distribution(generator)];
207 }
208 out += '-';
209 for (uint16_t i = 0; i < 3; i++) {
210 for (uint16_t j = 0; j < 4; j++) {
211 out += chars[distribution(generator)];
212 }
213 out += '-';
214 }
215 for (uint16_t i = 0; i < 12; i++) {
216 out += chars[distribution(generator)];
217 }
218
219 return out;
220}
221
222std::string string::padNumber(int64_t number, int width) {
223 return std::format("{:0>{}}", number, width);
224}
225
226void string::normalizeSlashes(std::string& path, bool stripSlashPrefix, bool stripSlashSuffix) {
227 std::ranges::replace(path, '\\', '/');
228 if (stripSlashPrefix && path.starts_with('/')) {
229 path = path.substr(1);
230 }
231 if (stripSlashSuffix && path.ends_with('/')) {
232 path.pop_back();
233 }
234}
235
236void string::denormalizeSlashes(std::string& path, bool stripSlashPrefix, bool stripSlashSuffix) {
237 std::replace(path.begin(), path.end(), '/', '\\');
238 if (stripSlashPrefix && path.starts_with('\\')) {
239 path = path.substr(1);
240 }
241 if (stripSlashSuffix && path.ends_with('\\')) {
242 path.pop_back();
243 }
244}
245
246std::from_chars_result string::toBool(std::string_view number, bool& out, int base) {
247 uint8_t tmp;
248 const auto result = std::from_chars(number.data(), number.data() + number.size(), tmp, base);
249 out = tmp;
250 return result;
251}
std::string createRandom(uint16_t length=32, std::string_view chars="0123456789_abcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ")
Definition String.cpp:186
std::string padNumber(int64_t number, int width)
Definition String.cpp:222
bool contains(std::string_view s, char c)
Definition String.cpp:21
void normalizeSlashes(std::string &path, bool stripSlashPrefix=false, bool stripSlashSuffix=true)
Definition String.cpp:226
std::from_chars_result toBool(std::string_view number, bool &out, int base=10)
Definition String.cpp:246
void ltrim(std::string &s)
Definition String.cpp:68
std::vector< std::string > split(std::string_view s, char delim)
Definition String.cpp:156
void denormalizeSlashes(std::string &path, bool stripSlashPrefix=false, bool stripSlashSuffix=true)
Definition String.cpp:236
bool matches(std::string_view in, std::string_view search)
A very basic regex-like pattern checker for ASCII strings.
Definition String.cpp:25
void trimInternal(std::string &s)
Definition String.cpp:99
void rtrim(std::string &s)
Definition String.cpp:79
void toUpper(std::string &input)
Definition String.cpp:176
void trim(std::string &s)
Definition String.cpp:90
bool iequals(std::string_view s1, std::string_view s2)
Definition String.cpp:62
void toLower(std::string &input)
Definition String.cpp:166
std::string generateUUIDv4()
Definition String.cpp:198