11#include < regex>
2+ #include < algorithm>
3+ #include < cctype>
24
35#include " StringHelper.h"
46
7+ // Private helper function to escape regex special characters
8+ std::string StringHelper::EscapeRegex (const std::string& str)
9+ {
10+ static constexpr std::string_view regex_chars = R"( \.+*?[]{}()|^$)" ;
11+ std::string result;
12+ result.reserve (str.size () * 2 ); // Reserve space to avoid reallocations
13+
14+ for (char c : str)
15+ {
16+ if (regex_chars.find (c) != std::string::npos)
17+ {
18+ result += ' \\ ' ;
19+ }
20+ result += c;
21+ }
22+
23+ return result;
24+ }
25+
26+ std::wstring StringHelper::EscapeRegex (const std::wstring& wstr)
27+ {
28+ static constexpr std::wstring_view regex_chars = LR"( \.+*?[]{}()|^$)" ;
29+ std::wstring result;
30+ result.reserve (wstr.size () * 2 );
31+
32+ for (wchar_t c : wstr)
33+ {
34+ if (regex_chars.find (c) != std::wstring::npos)
35+ {
36+ result += L' \\ ' ;
37+ }
38+ result += c;
39+ }
40+
41+ return result;
42+ }
43+
544std::string StringHelper::ReplaceAll (const std::string& str, const std::string& search, const std::string& replace)
645{
7- return std::regex_replace (str, std::regex (search), replace);
46+ if (search.empty ())
47+ {
48+ return str;
49+ }
50+
51+ try
52+ {
53+ return std::regex_replace (str, std::regex (search), replace);
54+ }
55+ catch (const std::regex_error&)
56+ {
57+ // If regex is invalid, fall back to literal replacement
58+ return ReplaceLiteral (str, search, replace);
59+ }
860}
961
1062std::wstring StringHelper::ReplaceAll (const std::wstring& wstr, const std::wstring& search, const std::wstring& replace)
1163{
12- return std::regex_replace (wstr, std::wregex (search), replace);
64+ if (search.empty ())
65+ {
66+ return wstr;
67+ }
68+
69+ try
70+ {
71+ return std::regex_replace (wstr, std::wregex (search), replace);
72+ }
73+ catch (const std::regex_error&)
74+ {
75+ // If regex is invalid, fall back to literal replacement
76+ return ReplaceLiteral (wstr, search, replace);
77+ }
78+ }
79+
80+ std::string StringHelper::ReplaceLiteral (const std::string& str, const std::string& search, const std::string& replace)
81+ {
82+ if (search.empty ())
83+ {
84+ return str;
85+ }
86+
87+ std::string result;
88+ result.reserve (str.size ());
89+ size_t lastPos = 0 ;
90+ size_t pos = str.find (search);
91+
92+ while (pos != std::string::npos)
93+ {
94+ result.append (str, lastPos, pos - lastPos);
95+ result.append (replace);
96+ lastPos = pos + search.length ();
97+ pos = str.find (search, lastPos);
98+ }
99+
100+ result.append (str, lastPos);
101+ return result;
102+ }
103+
104+ std::wstring StringHelper::ReplaceLiteral (const std::wstring& wstr, const std::wstring& search, const std::wstring& replace)
105+ {
106+ if (search.empty ())
107+ {
108+ return wstr;
109+ }
110+
111+ std::wstring result;
112+ result.reserve (wstr.size ());
113+ size_t lastPos = 0 ;
114+ size_t pos = wstr.find (search);
115+
116+ while (pos != std::wstring::npos)
117+ {
118+ result.append (wstr, lastPos, pos - lastPos);
119+ result.append (replace);
120+ lastPos = pos + search.length ();
121+ pos = wstr.find (search, lastPos);
122+ }
123+
124+ result.append (wstr, lastPos);
125+ return result;
13126}
14127
15128std::wstring StringHelper::ToWstring (const std::string& str, UINT codePage)
@@ -57,9 +170,17 @@ std::string StringHelper::ToString(const std::wstring& wstr, UINT codePage)
57170
58171std::vector<std::string> StringHelper::Split (const std::string& input, const std::string& delim)
59172{
60- // Vector is created on stack and copied on return
61173 std::vector<std::string> tokens;
62174
175+ if (input.empty () || delim.empty ())
176+ {
177+ if (!input.empty ())
178+ {
179+ tokens.push_back (input);
180+ }
181+ return tokens;
182+ }
183+
63184 // Skip delimiters at beginning.
64185 auto lastPos = input.find_first_not_of (delim, 0 );
65186 // Find first "non-delimiter".
@@ -74,14 +195,23 @@ std::vector<std::string> StringHelper::Split(const std::string& input, const std
74195 // Find next "non-delimiter"
75196 pos = input.find_first_of (delim, lastPos);
76197 }
198+
77199 return tokens;
78200}
79201
80202std::vector<std::wstring> StringHelper::Split (const std::wstring& input, const std::wstring& delim)
81203{
82- // Vector is created on stack and copied on return
83204 std::vector<std::wstring> tokens;
84205
206+ if (input.empty () || delim.empty ())
207+ {
208+ if (!input.empty ())
209+ {
210+ tokens.push_back (input);
211+ }
212+ return tokens;
213+ }
214+
85215 // Skip delimiters at beginning.
86216 auto lastPos = input.find_first_not_of (delim, 0 );
87217 // Find first "non-delimiter".
@@ -96,6 +226,7 @@ std::vector<std::wstring> StringHelper::Split(const std::wstring& input, const s
96226 // Find next "non-delimiter"
97227 pos = input.find_first_of (delim, lastPos);
98228 }
229+
99230 return tokens;
100231}
101232
0 commit comments