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