1
2
3
4
5
6 namespace System
7 {
8 public string TrimEnd(const string& s)
9 {
10 long i = s.Length();
11 while (i > 0 && IsSpace(s[i - 1]))
12 {
13 --i;
14 }
15 return s.Substring(0, i);
16 }
17
18 public ustring TrimEnd(const ustring& s)
19 {
20 long i = s.Length();
21 while (i > 0 && IsSpace(cast<char>(s[i - 1])))
22 {
23 --i;
24 }
25 return s.Substring(0, i);
26 }
27
28 public string Trim(const string& s)
29 {
30 long b = 0;
31 while (b < s.Length() && IsSpace(s[b]))
32 {
33 ++b;
34 }
35 long e = s.Length() - 1;
36 while (e >= b && IsSpace(s[e]))
37 {
38 --e;
39 }
40 return s.Substring(b, e - b + 1);
41 }
42
43 [nodiscard]
44 public Result<wstring> Trim(const wstring& s)
45 {
46 auto result = ToUtf32(s);
47 if (result.Error())
48 {
49 return Result<wstring>(ErrorId(result.GetErrorId()));
50 }
51 auto trimResult = Trim(result.Value());
52 if (trimResult.Error())
53 {
54 return Result<wstring>(ErrorId(trimResult.GetErrorId()));
55 }
56 return ToUtf16(trimResult.Value());
57 }
58
59 [nodiscard]
60 public Result<ustring> Trim(const ustring& s)
61 {
62 long b = 0;
63 bool stop = false;
64 while (b < s.Length() && !stop)
65 {
66 auto wsResult = IsWhiteSpace(s[b]);
67 if (wsResult.Error())
68 {
69 return Result<ustring>(ErrorId(wsResult.GetErrorId()));
70 }
71 stop = !wsResult.Value();
72 if (!stop)
73 {
74 ++b;
75 }
76 }
77 long e = s.Length() - 1;
78 stop = false;
79 while (e >= b && !stop)
80 {
81 auto wsResult = IsWhiteSpace(s[e]);
82 if (wsResult.Error())
83 {
84 return Result<ustring>(ErrorId(wsResult.GetErrorId()));
85 }
86 stop = !wsResult.Value();
87 if (!stop)
88 {
89 --e;
90 }
91 }
92 return Result<ustring>(s.Substring(b, e - b + 1));
93 }
94
95 public string TrimAll(const string& s)
96 {
97 string result;
98 result.Reserve(s.Length());
99 int state = 0;
100 for (char c : s)
101 {
102 switch (state)
103 {
104 case 0:
105 {
106 if (!IsSpace(c))
107 {
108 result.Append(c);
109 state = 1;
110 }
111 break;
112 }
113 case 1:
114 {
115 if (IsSpace(c))
116 {
117 state = 2;
118 }
119 else
120 {
121 result.Append(c);
122 }
123 break;
124 }
125 case 2:
126 {
127 if (!IsSpace(c))
128 {
129 result.Append(' ');
130 result.Append(c);
131 state = 1;
132 }
133 break;
134 }
135 }
136 }
137 return result;
138 }
139
140 [nodiscard]
141 public Result<wstring> TrimAll(const wstring& s)
142 {
143 auto result = ToUtf32(s);
144 if (result.Error())
145 {
146 return Result<wstring>(ErrorId(result.GetErrorId()));
147 }
148 auto trimResult = TrimAll(result.Value());
149 if (trimResult.Error())
150 {
151 return Result<wstring>(ErrorId(trimResult.GetErrorId()));
152 }
153 return ToUtf16(trimResult.Value());
154 }
155
156 [nodiscard]
157 public Result<ustring> TrimAll(const ustring& s)
158 {
159 ustring result;
160 result.Reserve(s.Length());
161 int state = 0;
162 for (uchar c : s)
163 {
164 switch (state)
165 {
166 case 0:
167 {
168 auto wsResult = IsWhiteSpace(c);
169 if (wsResult.Error())
170 {
171 return Result<ustring>(ErrorId(wsResult.GetErrorId()));
172 }
173 if (!wsResult.Value())
174 {
175 result.Append(c);
176 state = 1;
177 }
178 break;
179 }
180 case 1:
181 {
182 auto wsResult = IsWhiteSpace(c);
183 if (wsResult.Error())
184 {
185 return Result<ustring>(ErrorId(wsResult.GetErrorId()));
186 }
187 if (wsResult.Value())
188 {
189 state = 2;
190 }
191 else
192 {
193 result.Append(c);
194 }
195 break;
196 }
197 case 2:
198 {
199 auto wsResult = IsWhiteSpace(c);
200 if (wsResult.Error())
201 {
202 return Result<ustring>(ErrorId(wsResult.GetErrorId()));
203 }
204 if (!wsResult.Value())
205 {
206 result.Append(u' ');
207 result.Append(c);
208 state = 1;
209 }
210 break;
211 }
212 }
213 }
214 return Result<ustring>(result);
215 }
216
217 [nodiscard]
218 public Result<string> HexEscape(char c)
219 {
220 auto result = ToHexString(cast<byte>(c));
221 if (result.Error())
222 {
223 return result;
224 }
225 return "\\x" + result.Value();
226 }
227
228 [nodiscard]
229 public Result<string> HexEscape(wchar c)
230 {
231 auto result = ToHexString(cast<ushort>(c));
232 if (result.Error())
233 {
234 return result;
235 }
236 return "\\x" + result.Value();
237 }
238
239 [nodiscard]
240 public Result<string> HexEscape(uchar c)
241 {
242 auto result = ToHexString(cast<uint>(c));
243 if (result.Error())
244 {
245 return result;
246 }
247 return "\\x" + result.Value();
248 }
249
250 [nodiscard]
251 public Result<string> CharStr(char c)
252 {
253 switch (c)
254 {
255 case '\\': return Result<string>("\\\\");
256 case '\"': return Result<string>("\\\"");
257 case '\'': return Result<string>("\\\'");
258 case '\a': return Result<string>("\\a");
259 case '\b': return Result<string>("\\b");
260 case '\f': return Result<string>("\\f");
261 case '\n': return Result<string>("\\n");
262 case '\r': return Result<string>("\\r");
263 case '\t': return Result<string>("\\t");
264 case '\v': return Result<string>("\\v");
265 case '\0': return Result<string>("\\0");
266 default:
267 {
268 if (IsPrintable(c))
269 {
270 return Result<string>(string(c));
271 }
272 else
273 {
274 return HexEscape(c);
275 }
276 }
277 }
278 return Result<string>(string());
279 }
280
281 [nodiscard]
282 public Result<string> MakeCharLiteral(char c)
283 {
284 if (c == '\"')
285 {
286 return Result<string>(string("\'\"\'"));
287 }
288 auto charStrResult = CharStr(c);
289 if (charStrResult.Error())
290 {
291 return Result<string>(ErrorId(charStrResult.GetErrorId()));
292 }
293 return Result<string>("\'" + charStrResult.Value() + "\'");
294 }
295
296 [nodiscard]
297 public Result<wstring> CharStr(wchar c)
298 {
299 Result<string> hexEscapeResult;
300 switch (c)
301 {
302 case w'\\': return Result<wstring>(w"\\\\");
303 case w'\"': return Result<wstring>(w"\\\"");
304 case w'\'': return Result<wstring>(w"\\\'");
305 case w'\a': return Result<wstring>(w"\\a");
306 case w'\b': return Result<wstring>(w"\\b");
307 case w'\f': return Result<wstring>(w"\\f");
308 case w'\n': return Result<wstring>(w"\\n");
309 case w'\r': return Result<wstring>(w"\\r");
310 case w'\t': return Result<wstring>(w"\\t");
311 case w'\v': return Result<wstring>(w"\\v");
312 case w'\0': return Result<wstring>(w"\\0");
313 default:
314 {
315 if (cast<ushort>(c) < 256u && IsPrintable(cast<char>(c)))
316 {
317 return Result<wstring>(wstring(c));
318 }
319 else
320 {
321 hexEscapeResult = HexEscape(c);
322 if (hexEscapeResult.Error())
323 {
324 return Result<wstring>(ErrorId(hexEscapeResult.GetErrorId()));
325 }
326 return ToUtf16(hexEscapeResult.Value());
327 }
328 }
329 }
330 return Result<wstring>(wstring());
331 }
332
333 [nodiscard]
334 public Result<ustring> CharStr(uchar c)
335 {
336 Result<string> hexEscapeResult;
337 switch (c)
338 {
339 case u'\\': return Result<ustring>(u"\\\\");
340 case u'\"': return Result<ustring>(u"\\\"");
341 case u'\'': return Result<ustring>(u"\\\'");
342 case u'\a': return Result<ustring>(u"\\a");
343 case u'\b': return Result<ustring>(u"\\b");
344 case u'\f': return Result<ustring>(u"\\f");
345 case u'\n': return Result<ustring>(u"\\n");
346 case u'\r': return Result<ustring>(u"\\r");
347 case u'\t': return Result<ustring>(u"\\t");
348 case u'\v': return Result<ustring>(u"\\v");
349 case u'\0': return Result<ustring>(u"\\0");
350 default:
351 {
352 if (cast<uint>(c) < 256u && IsPrintable(cast<char>(c)))
353 {
354 return Result<ustring>(ustring(c));
355 }
356 else
357 {
358 hexEscapeResult = HexEscape(c);
359 if (hexEscapeResult.Error())
360 {
361 return Result<ustring>(ErrorId(hexEscapeResult.GetErrorId()));
362 }
363 return ToUtf32(hexEscapeResult.Value());
364 }
365 }
366 }
367 return Result<ustring>(ustring());
368 }
369
370 [nodiscard]
371 public Result<string> StringStr(const string& s)
372 {
373 string result;
374 for (char c : s)
375 {
376 if (c == '\'')
377 {
378 result.Append(c);
379 }
380 else
381 {
382 auto charStrResult = CharStr(c);
383 if (charStrResult.Error())
384 {
385 return Result<string>(ErrorId(charStrResult.GetErrorId()));
386 }
387 result.Append(charStrResult.Value());
388 }
389 }
390 return Result<string>(result);
391 }
392
393 [nodiscard]
394 public Result<ustring> StringStr(const ustring& s)
395 {
396 ustring result;
397 for (uchar c : s)
398 {
399 if (c == u'\'')
400 {
401 result.Append(c);
402 }
403 else
404 {
405 auto charStrResult = CharStr(c);
406 if (charStrResult.Error())
407 {
408 return Result<ustring>(ErrorId(charStrResult.GetErrorId()));
409 }
410 result.Append(charStrResult.Value());
411 }
412 }
413 return Result<ustring>(result);
414 }
415
416 [nodiscard]
417 public Result<string> MakeStringLiteral(const string& s)
418 {
419 string result = "\"";
420 auto stringStrResult = StringStr(s);
421 if (stringStrResult.Error())
422 {
423 return Result<string>(ErrorId(stringStrResult.GetErrorId()));
424 }
425 result.Append(stringStrResult.Value());
426 result.Append('\"');
427 return Result<string>(result);
428 }
429
430 [nodiscard]
431 public Result<ustring> MakeStringLiteral(const ustring& s)
432 {
433 ustring result = u"\"";
434 auto stringStrResult = StringStr(s);
435 if (stringStrResult.Error())
436 {
437 return Result<ustring>(ErrorId(stringStrResult.GetErrorId()));
438 }
439 result.Append(stringStrResult.Value());
440 result.Append(u'\"');
441 return Result<ustring>(result);
442 }
443
444 public string Unescape(const string& stringStr)
445 {
446 string result;
447 int state = 0;
448 for (char c : stringStr)
449 {
450 switch (state)
451 {
452 case 0:
453 {
454 if (c == '\\')
455 {
456 state = 1;
457 }
458 else
459 {
460 result.Append(c);
461 }
462 break;
463 }
464 case 1:
465 {
466 switch (c)
467 {
468 case '\\':
469 case '\"':
470 case '\'':
471 {
472 result.Append(c);
473 break;
474 }
475 case 'n':
476 {
477 result.Append("\n");
478 break;
479 }
480 default:
481 {
482 result.Append('\\').Append(c);
483 break;
484 }
485 }
486 state = 0;
487 break;
488 }
489 }
490 }
491 return result;
492 }
493
494 public ustring Unescape(const ustring& stringStr)
495 {
496 ustring result;
497 int state = 0;
498 for (uchar c : stringStr)
499 {
500 switch (state)
501 {
502 case 0:
503 {
504 if (c == '\\')
505 {
506 state = 1;
507 }
508 else
509 {
510 result.Append(c);
511 }
512 break;
513 }
514 case 1:
515 {
516 switch (c)
517 {
518 case '\\':
519 case '\"':
520 case '\'':
521 {
522 result.Append(c);
523 break;
524 }
525 case 'n':
526 {
527 result.Append('\n');
528 break;
529 }
530 default:
531 {
532 result.Append('\\').Append(c);
533 break;
534 }
535 }
536 state = 0;
537 break;
538 }
539 }
540 }
541 return result;
542 }
543
544 public enum FormatWidth
545 {
546 exact, min
547 }
548
549 public enum FormatJustify
550 {
551 left, right
552 }
553
554 public string Format(const string& s, int width)
555 {
556 return Format(s, width, FormatWidth.exact, FormatJustify.left);
557 }
558
559 public string Format(const string& s, int width, FormatJustify justify)
560 {
561 return Format(s, width, FormatWidth.exact, justify);
562 }
563
564 public string Format(const string& s, int width, FormatWidth fw)
565 {
566 return Format(s, width, fw, FormatJustify.left);
567 }
568
569 public string Format(const string& s, int width, FormatWidth fw, FormatJustify justify)
570 {
571 return Format(s, width, fw, justify, ' ');
572 }
573
574 public string Format(const string& s, int width, FormatWidth fw, FormatJustify justify, char fillChar)
575 {
576 string result;
577 int m = cast<int>(s.Length());
578 if (fw == FormatWidth.min)
579 {
580 width = Max(width, m);
581 }
582 else if (fw == FormatWidth.exact)
583 {
584 m = Min(m, width);
585 }
586 int n = Max(0, width - m);
587 if (justify == FormatJustify.right)
588 {
589 for (int i = 0; i < n; ++i;)
590 {
591 result.Append(fillChar);
592 }
593 }
594 for (int i = 0; i < m; ++i;)
595 {
596 result.Append(s[i]);
597 }
598 if (justify == FormatJustify.left)
599 {
600 for (int i = 0; i < n; ++i;)
601 {
602 result.Append(fillChar);
603 }
604 }
605 return result;
606 }
607
608 public ustring Format(const ustring& s, int width)
609 {
610 return Format(s, width, FormatWidth.exact, FormatJustify.left);
611 }
612
613 public ustring Format(const ustring& s, int width, FormatJustify justify)
614 {
615 return Format(s, width, FormatWidth.exact, justify);
616 }
617
618 public ustring Format(const ustring& s, int width, FormatWidth fw, FormatJustify justify)
619 {
620 return Format(s, width, fw, justify, ' ');
621 }
622
623 public ustring Format(const ustring& s, int width, FormatWidth fw, FormatJustify justify, char fillChar)
624 {
625 ustring result;
626 int m = cast<int>(s.Length());
627 if (fw == FormatWidth.min)
628 {
629 width = Max(width, m);
630 }
631 else if (fw == FormatWidth.exact)
632 {
633 m = Min(m, width);
634 }
635 int n = Max(0, width - m);
636 if (justify == FormatJustify.right)
637 {
638 for (int i = 0; i < n; ++i;)
639 {
640 result.Append(fillChar);
641 }
642 }
643 for (int i = 0; i < m; ++i;)
644 {
645 result.Append(s[i]);
646 }
647 if (justify == FormatJustify.left)
648 {
649 for (int i = 0; i < n; ++i;)
650 {
651 result.Append(fillChar);
652 }
653 }
654 return result;
655 }