DotNetDupe 4.0.6
C++17/20 Implementation of the .NET Base Class Library (BCL)
Loading...
Searching...
No Matches
String.cpp
Go to the documentation of this file.
1#include "pch.h"
2#include "System/String.h"
3#include "System/Array.h"
10#include <set>
11#include <vector>
12#include <initializer_list>
13#include <sstream>
14#include <type_traits>
15#include <algorithm>
16#include <iostream>
17#include <string>
18
19
20namespace DotNetDupe {
21 namespace System {
22
23 struct String::StringImpl {
24 std::string s;
25 StringImpl() = default;
26 StringImpl(const char* str) : s(str) {}
27 StringImpl(const std::string& str) : s(str) {}
28 StringImpl(std::string&& str) : s(std::move(str)) {}
29
30 };
31
32
33 namespace {
34 template <typename T>
35 inline String ToStringHelper(const T& val) {
36 using DecayedT = std::decay_t<T>;
37 if constexpr (std::is_same_v<DecayedT, String>) {
38 return val;
39 }
40 else if constexpr (std::is_same_v<DecayedT, std::string>) {
41 return String(val.c_str());
42 }
43 else if constexpr (std::is_same_v<DecayedT, std::nullptr_t>) {
44 return String("");
45 }
46 else if constexpr (std::is_same_v<DecayedT, bool>) {
47 return val ? "True" : "False";
48 }
49 else {
50 std::ostringstream ss;
51 ss << val;
52 return String(ss.str().c_str());
53 }
54 }
55 }
56
57 void ThrowArgumentException(const char* msg) {
58 throw ArgumentException(msg);
59 }
60
61 void ThrowFormatException(const char* msg) {
62 throw FormatException(msg);
63 }
64 String::String() { m_pImpl = new StringImpl(""); }
65 String::~String() { delete m_pImpl; }
66
67 static void AppendExplicitArg(const std::string& sFmt, size_t i, size_t end, const String* pArgs, int iArgCount, std::string& sRes) {
69 std::string num = sFmt.substr(i + 1, end - i - 1);
70 size_t idx = 0;
71 int argIdx = std::stoi(num, &idx);
72 if (idx != num.length() || argIdx < 0 || argIdx >= iArgCount) throw FormatException("Index out of bounds");
73
75 sRes += pArgs[argIdx].GetRawString() ? pArgs[argIdx].GetRawString() : "";
76 }
77
78 static void FormatOpenBrace(const std::string& sFmt, size_t& i, int& iAutoIndex, const String* pArgs, int iArgCount, std::string& sRes) {
80 if (i + 1 < sFmt.length() && sFmt[i+1] == '{') {
81 sRes += '{'; i++;
82 } else if (i + 1 < sFmt.length() && sFmt[i+1] == '}') {
84 if (iAutoIndex >= iArgCount) throw FormatException("Index out of bounds");
85 sRes += pArgs[iAutoIndex].GetRawString() ? pArgs[iAutoIndex].GetRawString() : "";
86 iAutoIndex++; i++;
87 } else {
89 size_t end = sFmt.find('}', i + 1);
90 if (end == std::string::npos) throw FormatException("Unclosed brace");
91 AppendExplicitArg(sFmt, i, end, pArgs, iArgCount, sRes);
92 i = end;
93 }
94 }
95
96 static void FormatClosingBrace(const std::string& sFmt, size_t& i, std::string& sRes) {
98 if (i + 1 < sFmt.length() && sFmt[i+1] == '}') {
99 sRes += '}'; i++;
100 } else {
102 throw FormatException("Unescaped closing brace");
103 }
104 }
105
106 String String::InternalFormat(const char* pFormat, const String* pArgs, int iArgCount) {
108 if (!pFormat) throw ArgumentException("Format string cannot be null.");
109 if (iArgCount == 0 || !pArgs) return String(pFormat);
110
112 std::string sFmt = pFormat;
113 std::string sRes;
114 int iAutoIndex = 0;
115 for (size_t i = 0; i < sFmt.length(); ++i) {
116 if (sFmt[i] == '{') {
117 FormatOpenBrace(sFmt, i, iAutoIndex, pArgs, iArgCount, sRes);
118 } else if (sFmt[i] == '}') {
119 FormatClosingBrace(sFmt, i, sRes);
120 } else {
121 sRes += sFmt[i];
122 }
123 }
124
126 return String(sRes.c_str());
127 }
128
129 void* String::operator new(size_t size) {
130 return ::operator new(size);
131 }
132
133 void String::operator delete(void* p) {
134 ::operator delete(p);
135 }
136
137 void* String::operator new[](size_t size) {
138 return ::operator new[](size);
139 }
140
141 void String::operator delete[](void* p) {
142 ::operator delete[](p);
143 }
144
145 String String::operator+(const char* pStr) const {
146 String sNewStr = *this;
147 if (pStr) {
148 sNewStr.m_pImpl->s.append(pStr);
149 }
150 return sNewStr;
151 }
152
153 String String::operator+(char ch) const {
154 String sNewStr = *this;
155 sNewStr.m_pImpl->s.push_back(ch);
156 return sNewStr;
157 }
158
160 m_pImpl->s.append(sStr.GetRawString());
161 return *this;
162 }
163
164 String& String::operator+=(const char* pStr) {
165 if (pStr) {
166 m_pImpl->s.append(pStr);
167 }
168 return *this;
169 }
170
172 m_pImpl->s.push_back(ch);
173 return *this;
174 }
175
176 String operator+(const char* pStr, const String& sStr) {
177 String newStr(pStr ? pStr : "");
178 return newStr + sStr;
179 }
180
181 String operator+(char ch, const String& sStr) {
182 char buf[2] = { ch, 0 };
183 String newStr(buf);
184 return newStr + sStr;
185 }
186
187
188 String::String(const char* pStr) {
189 if (pStr == nullptr) throw ArgumentException("Invalid input pointer");
190 m_pImpl = new StringImpl();
191 m_pImpl->s = pStr;
192 }
193
194 String::String(const String& sStr) { m_pImpl = new StringImpl(sStr.m_pImpl->s); }
195
197 if (this != &sStr) {
198 m_pImpl->s = sStr.m_pImpl->s;
199 }
200 return *this;
201 }
202
203 String::String(String&& sStr) noexcept { m_pImpl = new StringImpl(std::move(sStr.m_pImpl->s)); }
204 String& String::operator=(String&& sStr) noexcept {
205 if (this != &sStr) {
206 m_pImpl->s = std::move(sStr.m_pImpl->s);
207 }
208 return *this;
209 }
210 String::String(const wchar_t* pStr) {
211 if (pStr == nullptr) throw ArgumentException("Invalid input pointer");
212 m_pImpl = new StringImpl();
213
214 m_pImpl->s = Utils::StringConvert::WCharToUtf8(pStr);
215 }
216
217 String& String::operator=(const wchar_t* pStr) {
218 if (pStr == nullptr) throw ArgumentException("Invalid input pointer");
219
220 m_pImpl->s = Utils::StringConvert::WCharToUtf8(pStr);
221
222 return *this;
223 }
224
225 String& String::operator=(const char* pStr) {
226 if (pStr == nullptr) throw ArgumentException("Invalid input pointer");
227 m_pImpl->s = pStr;
228 return *this;
229 }
230 const char* String::GetRawString() const {
231 return m_pImpl->s.c_str();
232 }
233 const char* String::GetChars() const {
234 return GetRawString();
235 }
237 const char* p = GetRawString();
238 if (!p) return 0;
239 unsigned int hash = 2166136261u;
240 while (*p) {
241 hash ^= (unsigned char)(*p);
242 hash *= 16777619u;
243 ++p;
244 }
245 return (int)hash;
246 }
247 int String::GetLength() const {
248 return static_cast<int>(m_pImpl->s.length());
249 }
250
252 return String(GetRawString());
253 }
254
255
256 char String::operator[](int iIndex) const {
257 if (iIndex >= (int)m_pImpl->s.size()) throw ArgumentOutOfRangeException("Invalid iIndex");
258 return GetRawString() [iIndex];
259 }
260 static std::string ToLowerString(const std::string& s) {
261 std::string res = s;
262 std::transform(res.begin(), res.end(), res.begin(), [](char ch) {
263 return static_cast<char>(std::tolower(static_cast<unsigned char>(ch)));
264 });
265 return res;
266 }
267
268 int String::Compare(const String& sStr1, int iIndex1, const String& sStr2, int iIndex2, int iLength, bool bIgnoreCase) {
269 if (!bIgnoreCase) {
270 return sStr1.m_pImpl->s.compare(iIndex1, iLength, sStr2.m_pImpl->s, iIndex2, iLength);
271 }
272 auto s1 = ToLowerString(sStr1.m_pImpl->s.substr(iIndex1, iLength));
273 auto s2 = ToLowerString(sStr2.m_pImpl->s.substr(iIndex2, iLength));
274 return s1.compare(s2);
275 }
276
277 int String::CompareTo(const String& sStr) const {
278 return m_pImpl->s.compare(sStr.GetRawString());
279 }
281 const std::initializer_list<String> sStrs) const {
282 String sNewStr = *this;
283 for (auto sStr : sStrs) {
284 sNewStr.m_pImpl->s.append(sStr.GetRawString());
285 }
286 return sNewStr;
287 }
289 const String& sStr) const {
290 return Concat({ sStr });
291 }
292 bool String::Contains(char ch) const {
293 return m_pImpl->s.find(ch) != std::string::npos;
294 }
295 bool String::Contains(const String& sStr) const {
296 return m_pImpl->s.find(sStr.m_pImpl->s) != std::string::npos;
297 }
298
299 void String::CopyTo(int iSourceIndex, char* pDestination,
300 int iDestinationIndex, int iDestArraySize,
301 int iCount) const {
302 if (nullptr == pDestination)
303 throw ArgumentException("Invalid destination buffer");
304 int iLen = GetLength();
305 if (iSourceIndex < 0 || iSourceIndex >= iLen)
306 throw ArgumentOutOfRangeException("Invalid iSourceIndex");
307 if (iCount > iLen)
309 "Source array size is smaller than iCount");
310 if (iCount > iDestArraySize)
312 "Destination array is smaller than iCount");
313 m_pImpl->s.copy(pDestination + iDestinationIndex, iCount, iSourceIndex);
314 }
315 bool String::EndsWith(char ch, bool bIgnoreCase) const {
316 auto iLen = m_pImpl->s.length();
317 if (iLen == 0) return false;
318 if (bIgnoreCase) {
319 return std::tolower(static_cast<unsigned char>(m_pImpl->s [iLen - 1])) == std::tolower(static_cast<unsigned char>(ch));
320 }
321 return m_pImpl->s [iLen - 1] == ch;
322 }
323 bool String::EndsWith(const String& sSuffix,
324 bool bIgnoreCase) const {
325 int iLen = GetLength();
326 int iSuffixLen = sSuffix.GetLength();
327 if (iSuffixLen > iLen) return false;
328
329 if (bIgnoreCase) {
330 return Compare(*this, iLen - iSuffixLen, sSuffix, 0, iSuffixLen, true) == 0;
331 }
332 return m_pImpl->s.compare(static_cast<size_t>(iLen - iSuffixLen), static_cast<size_t>(iSuffixLen), sSuffix.m_pImpl->s) == 0;
333 }
334 bool String::Equals(const String& sStr1,
335 const String& sStr2) {
336 return sStr1 == sStr2;
337 }
338 bool String::Equals(const String& sStr) const {
339 return *this == sStr;
340 }
341 int String::IndexOf(const String& sSubstring) const {
342 return IndexOf(sSubstring, 0, false);
343 }
344 int String::IndexOf(const String& sSubstring,
345 bool bIgnoreCase) const {
346 return IndexOf(sSubstring, 0, bIgnoreCase);
347 }
348 int String::IndexOf(const String& sSubstring,
349 int iStartIndex, bool bIgnoreCase) const {
350 if (iStartIndex < 0 || iStartIndex > GetLength())
351 throw ArgumentOutOfRangeException("Invalid iStartIndex");
352
353 if (sSubstring.IsEmpty()) return iStartIndex;
354
355 if (!bIgnoreCase) {
356 auto pos = m_pImpl->s.find(sSubstring.m_pImpl->s, iStartIndex);
357 return (pos == std::string::npos) ? -1 : (int)pos;
358 }
359
360 // Case-insensitive search
361 auto it = std::search(
362 m_pImpl->s.begin() + iStartIndex, m_pImpl->s.end(),
363 sSubstring.m_pImpl->s.begin(), sSubstring.m_pImpl->s.end(),
364 [](char c1, char c2) { return std::tolower(static_cast<unsigned char>(c1)) == std::tolower(static_cast<unsigned char>(c2)); }
365 );
366
367 return (it == m_pImpl->s.end()) ? -1 : (int)std::distance(m_pImpl->s.begin(), it);
368 }
369 int String::IndexOfAny(int iStartIndex,
370 std::initializer_list<char> chChars) {
371 if (iStartIndex < 0 || iStartIndex > GetLength())
372 throw ArgumentOutOfRangeException("Invalid iStartIndex");
373
374 auto pos = m_pImpl->s.find_first_of(std::string(chChars.begin(), chChars.end()), iStartIndex);
375 return (pos == std::string::npos) ? -1 : (int)pos;
376 }
377
378
379
380 String& String::Append(const char ch) {
381 m_pImpl->s += ch;
382 return *this;
383 }
385 const String& sStr) {
386 m_pImpl->s.append(sStr.GetRawString());
387 return *this;
388 }
390 int iIndex, const String& sStr) {
391 int iLen = GetLength();
392 if (iIndex < 0 || iIndex > iLen)
393 throw ArgumentOutOfRangeException("Invalid iIndex");
394
395 m_pImpl->s.insert(iIndex, sStr.GetRawString(), sStr.GetLength());
396 return *this;
397 }
398 bool String::IsEmpty() const {
399 return m_pImpl->s.empty();
400 }
401
403 char chSeparator, std::initializer_list<String> sStrings) {
404 return Join(chSeparator, sStrings, 0, (int)sStrings.size());
405 }
407 char chSeparator, std::initializer_list<String> sStrings,
408 int iStartIndex, int iCount) {
409 if (iStartIndex < 0 || iStartIndex > (int)sStrings.size())
410 throw ArgumentOutOfRangeException("Invalid iStartIndex");
411 if (iCount < 0 || (iStartIndex + iCount) > (int)sStrings.size())
412 throw ArgumentOutOfRangeException("Invalid iCount");
413
414 const String* pStrs = sStrings.begin();
415 String sJoinStr("");
416
417 for (int i = iStartIndex; i < iStartIndex + iCount; i++) {
418 sJoinStr.Append(pStrs[i]);
419 if (i != iStartIndex + iCount - 1) {
420 sJoinStr.Append(chSeparator);
421 }
422 }
423 return sJoinStr;
424 }
426 const String& sSeparator,
427 std::initializer_list<String> sStrings) {
428 return Join(sSeparator, sStrings, 0, (int)sStrings.size());
429 }
431 const String& sSeparator,
432 std::initializer_list<String> sStrings, int iStartIndex,
433 int iCount) {
434 if (iStartIndex < 0 || iStartIndex > (int)sStrings.size())
435 throw ArgumentOutOfRangeException("Invalid iStartIndex");
436 if (iCount < 0 || (iStartIndex + iCount) > (int)sStrings.size())
437 throw ArgumentOutOfRangeException("Invalid iCount");
438
439 const String* pStrs = sStrings.begin();
440 String sJoinStr("");
441
442 for (int i = iStartIndex; i < iStartIndex + iCount; i++) {
443 sJoinStr.Append(pStrs[i]);
444 if (i != iStartIndex + iCount - 1) {
445 sJoinStr.Append(sSeparator);
446 }
447 }
448 return sJoinStr;
449 }
451 bool bIgnoreCase) {
452 if (sStr.IsEmpty()) return GetLength();
453
454 if (!bIgnoreCase) {
455 auto pos = m_pImpl->s.rfind(sStr.m_pImpl->s);
456 return (pos == std::string::npos) ? -1 : (int)pos;
457 }
458
459 auto it = std::find_end(
460 m_pImpl->s.begin(), m_pImpl->s.end(),
461 sStr.m_pImpl->s.begin(), sStr.m_pImpl->s.end(),
462 [](char c1, char c2) { return std::tolower(static_cast<unsigned char>(c1)) == std::tolower(static_cast<unsigned char>(c2)); }
463 );
464
465 return (it == m_pImpl->s.end()) ? -1 : (int)std::distance(m_pImpl->s.begin(), it);
466 }
467
468 static int FindLastCharIndex(const std::string& s, int iStartIndex, char ch, bool bIgnoreCase) {
469 for (int i = static_cast<int>(s.length()) - 1; i >= iStartIndex; --i) {
470 bool match = bIgnoreCase
471 ? std::tolower(static_cast<unsigned char>(s[i])) == std::tolower(static_cast<unsigned char>(ch))
472 : (s[i] == ch);
473 if (match) return i;
474 }
475 return -1;
476 }
477
478 int String::LastIndexOfAny(int iStartIndex, std::initializer_list<char> chChars, bool bIgnoreCase) {
479 if (iStartIndex < 0 || iStartIndex > GetLength()) throw ArgumentOutOfRangeException("Invalid iStartIndex");
480 if (IsEmpty()) return -1;
481
482 for (auto ch : chChars) {
483 int idx = FindLastCharIndex(m_pImpl->s, iStartIndex, ch, bIgnoreCase);
484 if (idx != -1) return idx;
485 }
486 return -1;
487 }
488 String String::PadLeft(int iTotalWidth) {
489 return PadLeft(iTotalWidth, (char)' ');
490 }
491 String String::PadLeft(int iTotalWidth,
492 char ch) {
493 if (iTotalWidth < 0) {
494 throw ArgumentException("Invalid iTotalWidth");
495 }
496 int iLen = GetLength();
497 if (iTotalWidth <= iLen) {
498 return *this;
499 }
500 std::string sPadding(iTotalWidth - iLen, ch);
501 m_pImpl->s.insert(0, sPadding);
502 return *this;
503 }
504 String String::PadRight(int iTotalWidth) {
505 return PadRight(iTotalWidth, (char)' ');
506 }
507 String String::PadRight(int iTotalWidth,
508 char ch) {
509 if (iTotalWidth < 0) {
510 throw ArgumentException("Invalid iTotalWidth");
511 }
512 int iLen = GetLength();
513 if (iTotalWidth <= iLen) {
514 return *this;
515 }
516 m_pImpl->s.append(iTotalWidth - iLen, ch);
517 return *this;
518 }
519 String String::Remove(int iStartIndex) const {
520 return Remove(iStartIndex, GetLength() - iStartIndex);
521 }
522 String String::Remove(int iStartIndex,
523 int iCount) const {
524 int iLen = GetLength();
525 if (iStartIndex < 0 || iStartIndex > iLen || iCount < 0 || (iStartIndex + iCount) > iLen) {
526 throw ArgumentOutOfRangeException("Invalid iStartIndex or iCount");
527 }
528
529 std::string sRet = m_pImpl->s;
530 sRet.erase(iStartIndex, iCount);
531 return String(sRet.c_str());
532 }
533 String String::Replace(char chOriginalChar,
534 char chReplaceChar) const {
535 std::string sRet = m_pImpl->s;
536 std::replace(sRet.begin(), sRet.end(), chOriginalChar, chReplaceChar);
537 return String(sRet.c_str());
538 }
540 const String& sOriginalStr,
541 const String& sReplaceStr) const {
542 if (sOriginalStr.IsEmpty()) return *this;
543
544 std::string sRet = m_pImpl->s;
545 size_t pos = 0;
546 while ((pos = sRet.find(sOriginalStr.m_pImpl->s, pos)) != std::string::npos) {
547 sRet.replace(pos, sOriginalStr.GetLength(), sReplaceStr.m_pImpl->s);
548 pos += sReplaceStr.GetLength();
549 }
550 return String(sRet.c_str());
551 }
552 Array<String> String::Split(char chSeparator) const {
553 std::vector<String> vTempResult;
554 std::stringstream ss(m_pImpl->s);
555 std::string sToken;
556 while (std::getline(ss, sToken, chSeparator)) {
557 vTempResult.push_back(String(sToken.c_str()));
558 }
559
560 Array<String> result((int)vTempResult.size());
561 for (int i = 0; i < (int)vTempResult.size(); i++) result [i] = vTempResult [i];
562 return result;
563 }
564
565 static void AddSplitToken(const std::string& sCurrent, StringSplitOptions eOptions, std::vector<String>& vResult) {
566 String s(sCurrent.c_str());
567 if (eOptions == StringSplitOptions::TrimEntries) s = s.Trim();
568 if (eOptions != StringSplitOptions::RemoveEmptyEntries || !s.IsEmpty()) {
569 vResult.push_back(s);
570 }
571 }
572
573 static std::set<char> PopulateSplitCharSet(const String* pSeparator, int iCount) {
574 std::set<char> charSet;
575 if (!pSeparator || iCount <= 0) return charSet;
576 for (int i = 0; i < iCount; ++i) {
577 const char* raw = pSeparator[i].GetRawString();
578 if (raw) { while (*raw) charSet.insert(*raw++); }
579 }
580 return charSet;
581 }
582
583 static std::vector<String> SplitByCharSet(const std::string& sText, const std::set<char>& charSet, StringSplitOptions eOptions) {
584 std::vector<String> vResult;
585 std::string sCurrent;
586 for (char c : sText) {
587 if (charSet.find(c) == charSet.end()) {
588 sCurrent += c;
589 } else {
590 AddSplitToken(sCurrent, eOptions, vResult);
591 sCurrent.clear();
592 }
593 }
594 AddSplitToken(sCurrent, eOptions, vResult);
595 return vResult;
596 }
597
598 Array<String> String::Split(const Array<String>& arrSeparators, StringSplitOptions eOptions) const {
599 return Split(arrSeparators.GetData(), arrSeparators.GetLength(), eOptions);
600 }
601
602 Array<String> String::Split(const String* pSeparator, int iCount, StringSplitOptions eOptions) const {
603 std::set<char> charSet = PopulateSplitCharSet(pSeparator, iCount);
604 std::vector<String> vTempResult = SplitByCharSet(m_pImpl->s, charSet, eOptions);
605 Array<String> result(static_cast<int>(vTempResult.size()));
606 for (int i = 0; i < result.GetLength(); i++) result[i] = vTempResult[i];
607 return result;
608 }
609
610 bool String::StartsWith(const String& sPrefix) const {
611 return StartsWith(sPrefix, false);
612 }
613
614 bool String::StartsWith(const String& sPrefix, bool bIgnoreCase) const {
615 if (sPrefix.GetLength() > GetLength()) return false;
616
617 if (!bIgnoreCase) {
618 return m_pImpl->s.compare(0, sPrefix.GetLength(), sPrefix.m_pImpl->s) == 0;
619 }
620
621 return Compare(*this, 0, sPrefix, 0, sPrefix.GetLength(), true) == 0;
622 }
623
625 return ValueOf(iValue);
626 }
627
629 return ToStringHelper(iValue);
630 }
631
632
633 String String::ValueOf(long long llValue) {
634 return ToStringHelper(llValue);
635 }
636
637 String String::ValueOf(double dValue) {
638 std::ostringstream ss;
639 ss << dValue;
640 return String(ss.str().c_str());
641 }
642
644 return ToStringHelper(iValue);
645 }
646
647 String String::ToString(long long llValue) {
648 return ToStringHelper(llValue);
649 }
650
651 String String::ToString(double dValue) {
652 return ToStringHelper(dValue);
653 }
654
656 return ToStringHelper(bValue);
657 }
658
659 String String::Substring(int iStartIndex) const {
660 return Substring(iStartIndex, GetLength() - iStartIndex);
661 }
662
663 String String::Substring(int iStartIndex, int iLength) const {
664 int iLen = GetLength();
665 if (iStartIndex < 0 || iStartIndex > iLen || iLength < 0 || (iStartIndex + iLength) > iLen) {
666 throw ArgumentOutOfRangeException("Invalid iStartIndex or iLength");
667 }
668 return String(m_pImpl->s.substr(iStartIndex, iLength).c_str());
669 }
670
671
673 std::string sRet = m_pImpl->s;
674 std::transform(sRet.begin(), sRet.end(), sRet.begin(), [](char ch) -> char {
675 return static_cast<char>(std::tolower(static_cast<unsigned char>(ch)));
676 });
677 return String(sRet.c_str());
678 }
679
681 std::string sRet = m_pImpl->s;
682 std::transform(sRet.begin(), sRet.end(), sRet.begin(), [](char ch) -> char {
683 return static_cast<char>(std::toupper(static_cast<unsigned char>(ch)));
684 });
685 return String(sRet.c_str());
686 }
687
689 return TrimStart().TrimEnd();
690 }
691
693 auto it = std::find_if(m_pImpl->s.begin(), m_pImpl->s.end(), [](char ch) {
694 return !std::isspace(static_cast<unsigned char>(ch));
695 });
696 if (it == m_pImpl->s.end()) return "";
697 return String(m_pImpl->s.substr(std::distance(m_pImpl->s.begin(), it)).c_str());
698 }
699
701 auto it = std::find_if(m_pImpl->s.rbegin(), m_pImpl->s.rend(), [](char ch) {
702 return !std::isspace(static_cast<unsigned char>(ch));
703 });
704 if (it == m_pImpl->s.rend()) return "";
705 return String(m_pImpl->s.substr(0, m_pImpl->s.length() - std::distance(m_pImpl->s.rbegin(), it)).c_str());
706 }
707 } // namespace System
708} // namespace DotNetDupe
Defines the exception thrown when an invalid argument is provided to a method.
Defines the exception thrown when an argument value is outside the acceptable range of values.
Provides methods for creating, manipulating, searching, and sorting arrays.
Defines the exception thrown when the format of an argument is invalid or not compliant with specific...
Defines the exception thrown when a requested method or operation is not implemented.
Defines the exception thrown when an arithmetic, casting, or conversion operation results in an overf...
High-performance UTF-8 / UTF-16 string manipulation class mirroring .NET System.String.
Utility routines for high-performance UTF-8, UTF-16, and wide-character string conversions.
ArgumentException(const String &sMessage)
Initializes a new instance of the ArgumentException class with a specified error message.
ArgumentOutOfRangeException(const String &sMessage)
Initializes a new instance of the ArgumentOutOfRangeException class with a specified error message.
Provides methods for creating, manipulating, searching, and sorting arrays, thereby serving as the ba...
Definition Array.h:29
int GetLength() const
Gets the total number of elements in all dimensions of the Array.
Definition Array.h:142
T * GetData()
Gets a pointer to the contiguous internal element buffer.
Definition Array.h:146
FormatException(const String &sMessage)
Initializes a new instance of the FormatException class with a specified error message.
Represents text as a sequence of UTF-8 code units with culture-invariant operations.
Definition String.h:74
static String ValueOf(int iValue)
Definition String.cpp:628
static String Join(char chSeparator, std::initializer_list< String > sStrings)
Definition String.cpp:402
String & operator+=(const String &sStr)
Definition String.cpp:159
String & operator=(const String &sStr)
Copy assignment operator.
Definition String.cpp:196
String Concat(const std::initializer_list< String > sStrs) const
Definition String.cpp:280
String Substring(int iStartIndex) const
Definition String.cpp:659
String ToLower() const
Definition String.cpp:672
const char * GetChars() const
Definition String.cpp:233
String operator+(const String &sStr) const
Definition String.cpp:288
int CompareTo(const String &sStr) const
Definition String.cpp:277
bool StartsWith(const String &sPrefix) const
Definition String.cpp:610
String PadLeft(int iTotalWidth)
Definition String.cpp:488
static int Compare(const String &sStr1, int iIndex1, const String &sStr2, int iIndex2, int iLength, bool bIgnoreCase)
Definition String.cpp:268
String Replace(char chOriginalChar, char chReplaceChar) const
Definition String.cpp:533
String & Insert(int iIndex, const String &sStr)
Definition String.cpp:389
void CopyTo(int iSourceIndex, char *pDestination, int iDestinationIndex, int iDestArraySize, int iCount) const
Definition String.cpp:299
static String FromInt(int iValue)
Definition String.cpp:624
String Remove(int iStartIndex) const
Definition String.cpp:519
bool EndsWith(char ch, bool bIgnoreCase) const
Definition String.cpp:315
int LastIndexOfAny(int iStartIndex, std::initializer_list< char > chChars, bool bIgnoreCase)
Definition String.cpp:478
static String ToString(int iValue)
Definition String.cpp:643
String()
Initializes a new instance of the String class to an empty string.
Definition String.cpp:64
String ToUpper() const
Definition String.cpp:680
String & Append(const char ch)
Definition String.cpp:380
int IndexOfAny(int iStartIndex, std::initializer_list< char > chChars)
Definition String.cpp:369
static bool Equals(const String &sStr1, const String &sStr2)
Definition String.cpp:334
int IndexOf(const String &sSubstring) const
Definition String.cpp:341
static String InternalFormat(const char *pFormat, const String *pArgs, int iArgCount)
Definition String.cpp:106
const char * GetRawString() const
Definition String.cpp:230
int LastIndexOf(const String &sStr, bool bIgnoreCase)
Definition String.cpp:450
bool Contains(char ch) const
Definition String.cpp:292
char operator[](int iIndex) const
Definition String.cpp:256
Array< String > Split(char chSeparator) const
Definition String.cpp:552
String TrimStart() const
Definition String.cpp:692
String PadRight(int iTotalWidth)
Definition String.cpp:504
String TrimEnd() const
Definition String.cpp:700
static std::string WCharToUtf8(const wchar_t *pWStr)
Converts a null-terminated UTF-16 wchar_t string into a UTF-8 std::string.
StringSplitOptions
Specifies whether applicable Overload:Split methods include or omit empty substrings.
Definition String.h:25
@ TrimEntries
Trim white-space characters from each element in the array.
Definition String.h:28
@ RemoveEmptyEntries
Omit substrings that contain an empty string from the array.
Definition String.h:27
static void AppendExplicitArg(const std::string &sFmt, size_t i, size_t end, const String *pArgs, int iArgCount, std::string &sRes)
Definition String.cpp:67
static std::string ToLowerString(const std::string &s)
Definition String.cpp:260
static void AddSplitToken(const std::string &sCurrent, StringSplitOptions eOptions, std::vector< String > &vResult)
Definition String.cpp:565
static std::vector< String > SplitByCharSet(const std::string &sText, const std::set< char > &charSet, StringSplitOptions eOptions)
Definition String.cpp:583
static std::set< char > PopulateSplitCharSet(const String *pSeparator, int iCount)
Definition String.cpp:573
void ThrowFormatException(const char *msg)
Definition String.cpp:61
void ThrowArgumentException(const char *msg)
Definition String.cpp:57
static int FindLastCharIndex(const std::string &s, int iStartIndex, char ch, bool bIgnoreCase)
Definition String.cpp:468
static void FormatOpenBrace(const std::string &sFmt, size_t &i, int &iAutoIndex, const String *pArgs, int iArgCount, std::string &sRes)
Definition String.cpp:78
static void FormatClosingBrace(const std::string &sFmt, size_t &i, std::string &sRes)
Definition String.cpp:96