1 // =================================
  2 // Copyright (c) 2021 Seppo Laakko
  3 // Distributed under the MIT license
  4 // =================================
  5 
  6 namespace System
  7 {
  8     public nothrow string Trim(const string& s)
  9     {
 10         long b = 0;
 11         while (b < s.Length() && IsSpace(s[b]))
 12         {
 13             ++b;
 14         }
 15         long e = s.Length() - 1;
 16         while (e >= b && IsSpace(s[e]))
 17         {
 18             --e;
 19         }
 20         return s.Substring(be - b + 1);
 21     }
 22 
 23     public wstring Trim(const wstring& s)
 24     {
 25         return ToUtf16(Trim(ToUtf32(s)));
 26     }
 27 
 28     public ustring Trim(const ustring& s)
 29     {
 30         long b = 0;
 31         while (b < s.Length() && IsWhiteSpace(s[b]))
 32         {
 33             ++b;
 34         }
 35         long e = s.Length() - 1;
 36         while (e >= b && IsWhiteSpace(s[e]))
 37         {
 38             --e;
 39         }
 40         return s.Substring(be - b + 1);
 41     }
 42 
 43     public string TrimAll(const string& s)
 44     {
 45         string result;
 46         result.Reserve(s.Length());
 47         int state = 0;
 48         for (char c : s)
 49         {
 50             switch (state)
 51             {
 52                 case 0:
 53                 {
 54                     if (!IsSpace(c))
 55                     {
 56                         result.Append(c);
 57                         state = 1;
 58                     }
 59                     break;
 60                 }
 61                 case 1:
 62                 {
 63                     if (IsSpace(c))
 64                     {
 65                         state = 2;
 66                     }
 67                     else
 68                     {
 69                         result.Append(c);
 70                     }
 71                     break;
 72                 }
 73                 case 2:
 74                 {
 75                     if (!IsSpace(c))
 76                     {
 77                         result.Append(' ');
 78                         result.Append(c);
 79                         state = 1;
 80                     }
 81                     break;
 82                 }
 83             }
 84         }
 85         return result;
 86     }
 87 
 88     public wstring TrimAll(const wstring& s)
 89     {
 90         return ToUtf16(TrimAll(ToUtf32(s)));
 91     }
 92 
 93     public ustring TrimAll(const ustring& s)
 94     {
 95         ustring result;
 96         result.Reserve(s.Length());
 97         int state = 0;
 98         for (uchar c : s)
 99         {
100             switch (state)
101             {
102                 case 0:
103                 {
104                     if (!IsWhiteSpace(c))
105                     {
106                         result.Append(c);
107                         state = 1;
108                     }
109                     break;
110                 }
111                 case 1:
112                 {
113                     if (IsWhiteSpace(c))
114                     {
115                         state = 2;
116                     }
117                     else
118                     {
119                         result.Append(c);
120                     }
121                     break;
122                 }
123                 case 2:
124                 {
125                     if (!IsWhiteSpace(c))
126                     {
127                         result.Append(u' ');
128                         result.Append(c);
129                         state = 1;
130                     }
131                     break;
132                 }
133             }
134         }
135         return result;
136     }
137 
138     public nothrow string HexEscape(char c)
139     {
140         return "\\x" + ToHexString(cast<byte>(c));
141     }
142 
143     public nothrow string HexEscape(wchar c)
144     {
145         return "\\x" + ToHexString(cast<ushort>(c));
146     }
147 
148     public nothrow string HexEscape(uchar c)
149     {
150         return "\\x" + ToHexString(cast<uint>(c));
151     }
152 
153     public nothrow string CharStr(char c)
154     {
155         switch (c)
156         {
157             case '\\': return "\\\\";
158             case '"':  return "\\\"";
159             case '\'': return "\\'";
160             case '\a': return "\\a";
161             case '\b': return "\\b";
162             case '\f': return "\\f";
163             case '\n': return "\\n";
164             case '\r': return "\\r";
165             case '\t': return "\\t";
166             case '\v': return "\\v";
167             case '\0': return "\\0";
168             default:
169             {
170                 if (IsPrintable(c))
171                 {
172                     return string(c);
173                 }
174                 else
175                 {
176                     return HexEscape(c);
177                 }
178             }
179         }
180         return string();
181     }
182 
183     public nothrow string MakeCharLiteral(char c)
184     {
185         if (c == '"')
186         {
187             return string("'\"'");
188         }
189         return "'" + CharStr(c) + "'";
190     }
191 
192 
193     public wstring CharStr(wchar c)
194     {
195         switch (c)
196         {
197             case w'\\': return w"\\\\";
198             case w'"':  return w"\\\"";
199             case w'\'': return w"\\'";
200             case w'\a': return w"\\a";
201             case w'\b': return w"\\b";
202             case w'\f': return w"\\f";
203             case w'\n': return w"\\n";
204             case w'\r': return w"\\r";
205             case w'\t': return w"\\t";
206             case w'\v': return w"\\v";
207             case w'\0': return w"\\0";
208             default:
209             {
210                 if (cast<ushort>(c) < 256u && IsPrintable(cast<char>(c)))
211                 {
212                     return wstring(c);
213                 }
214                 else
215                 {
216                     return ToUtf16(HexEscape(c));
217                 }
218             }
219         }
220         return wstring();
221     }
222 
223     public ustring CharStr(uchar c)
224     {
225         switch (c)
226         {
227             case u'\\': return u"\\\\";
228             case u'"':  return u"\\\"";
229             case u'\'': return u"\\'";
230             case u'\a': return u"\\a";
231             case u'\b': return u"\\b";
232             case u'\f': return u"\\f";
233             case u'\n': return u"\\n";
234             case u'\r': return u"\\r";
235             case u'\t': return u"\\t";
236             case u'\v': return u"\\v";
237             case u'\0': return u"\\0";
238             default:
239             {
240                 if (cast<uint>(c) < 256u && IsPrintable(cast<char>(c)))
241                 {
242                     return ustring(c);
243                 }
244                 else
245                 {
246                     return ToUtf32(HexEscape(c));
247                 }
248             }
249         }
250         return ustring();
251     }
252 
253     public nothrow string StringStr(const string& s)
254     {
255         string result;
256         for (char c : s)
257         {
258             if (c == '\'')
259             {
260                 result.Append(c);
261             }
262             else
263             {
264                 result.Append(CharStr(c));
265             }
266         }
267         return result;
268     }
269 
270     public ustring StringStr(const ustring& s)
271     {
272         ustring result;
273         for (uchar c : s)
274         {
275             if (c == u'\'')
276             {
277                 result.Append(c);
278             }
279             else
280             {
281                 result.Append(CharStr(c));
282             }
283         }
284         return result;
285     }
286 
287     public nothrow string MakeStringLiteral(const string& s)
288     {
289         string result = "\"";
290         result.Append(StringStr(s));
291         result.Append('"');
292         return result;
293     }
294 
295     public ustring MakeStringLiteral(const ustring& s)
296     {
297         ustring result = u"\"";
298         result.Append(StringStr(s));
299         result.Append(u'"');
300         return result;
301     }
302 
303     public nothrow string Unescape(const string& stringStr)
304     {
305         string result;
306         int state = 0;
307         for (char c : stringStr)
308         {
309             switch (state)
310             {
311                 case 0:
312                 {
313                     if (c == '\\')
314                     {
315                         state = 1;
316                     }
317                     else
318                     {
319                         result.Append(c);
320                     }
321                     break;
322                 }
323                 case 1:
324                 {
325                     switch (c)
326                     {
327                         case '\\':
328                         case '"':
329                         case '\'':
330                         {
331                             result.Append(c);
332                             break;
333                         }
334                         case 'n':
335                         {
336                             result.Append("\n");
337                             break;
338                         }
339                         default:
340                         {
341                             result.Append('\\').Append(c);
342                             break;
343                         }
344                     }
345                     state = 0;
346                     break;
347                 }
348             }
349         }
350         return result;
351     }
352 
353     public nothrow ustring Unescape(const ustring& stringStr)
354     {
355         ustring result;
356         int state = 0;
357         for (uchar c : stringStr)
358         {
359             switch (state)
360             {
361                 case 0:
362                 {
363                     if (c == '\\')
364                     {
365                         state = 1;
366                     }
367                     else
368                     {
369                         result.Append(c);
370                     }
371                     break;
372                 }
373                 case 1:
374                 {
375                     switch (c)
376                     {
377                         case '\\':
378                         case '"':
379                         case '\'':
380                         {
381                             result.Append(c);
382                             break;
383                         }
384                         case 'n':
385                         {
386                             result.Append('\n');
387                             break;
388                         }
389                         default:
390                         {
391                             result.Append('\\').Append(c);
392                             break;
393                         }
394                     }
395                     state = 0;
396                     break;
397                 }
398             }
399         }
400         return result;
401     }
402 
403     public enum FormatWidth
404     {
405         exactmin
406     }
407 
408     public enum FormatJustify
409     {
410         leftright
411     }
412 
413     public nothrow string Format(const string& sint width)
414     {
415         return Format(swidthFormatWidth.exactFormatJustify.left);
416     }
417 
418     public nothrow string Format(const string& sint widthFormatJustify justify)
419     {
420         return Format(swidthFormatWidth.exactjustify);
421     }
422 
423     public nothrow string Format(const string& sint widthFormatWidth fw)
424     {
425         return Format(swidthfwFormatJustify.left);
426     }
427 
428     public nothrow string Format(const string& sint widthFormatWidth fwFormatJustify justify)
429     {
430         return Format(swidthfwjustify' ');
431     }
432 
433     public nothrow string Format(const string& sint widthFormatWidth fwFormatJustify justifychar fillChar)
434     {
435         string result;
436         int m = cast<int>(s.Length());
437         if (fw == FormatWidth.min)
438         {
439             width = Max(widthm);
440         }
441         else if (fw == FormatWidth.exact)
442         {
443             m = Min(mwidth);
444         }
445         int n = Max(0width - m);
446         if (justify == FormatJustify.right)
447         {
448             for (int i = 0; i < n; ++i;)
449             {
450                 result.Append(fillChar);
451             }
452         }
453         for (int i = 0; i < m; ++i;)
454         {
455             result.Append(s[i]);
456         }
457         if (justify == FormatJustify.left)
458         {
459             for (int i = 0; i < n; ++i;)
460             {
461                 result.Append(fillChar);
462             }
463         }
464         return result;
465     }
466 
467     public nothrow ustring Format(const ustring& sint width)
468     {
469         return Format(swidthFormatWidth.exactFormatJustify.left);
470     }
471 
472     public nothrow ustring Format(const ustring& sint widthFormatJustify justify)
473     {
474         return Format(swidthFormatWidth.exactjustify);
475     }
476 
477     public nothrow ustring Format(const ustring& sint widthFormatWidth fwFormatJustify justify)
478     {
479         return Format(swidthfwjustify' ');
480     }
481 
482     public nothrow ustring Format(const ustring& sint widthFormatWidth fwFormatJustify justifychar fillChar)
483     {
484         ustring result;
485         int m = cast<int>(s.Length());
486         if (fw == FormatWidth.min)
487         {
488             width = Max(widthm);
489         }
490         else if (fw == FormatWidth.exact)
491         {
492             m = Min(mwidth);
493         }
494         int n = Max(0width - m);
495         if (justify == FormatJustify.right)
496         {
497             for (int i = 0; i < n; ++i;)
498             {
499                 result.Append(fillChar);
500             }
501         }
502         for (int i = 0; i < m; ++i;)
503         {
504             result.Append(s[i]);
505         }
506         if (justify == FormatJustify.left)
507         {
508             for (int i = 0; i < n; ++i;)
509             {
510                 result.Append(fillChar);
511             }
512         }
513         return result;
514     }
515 }