MezzanineEngine 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
stringtool.cpp
1 // © Copyright 2010 - 2014 BlackTopp Studios Inc.
2 /* This file is part of The Mezzanine Engine.
3 
4  The Mezzanine Engine is free software: you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation, either version 3 of the License, or
7  (at your option) any later version.
8 
9  The Mezzanine Engine is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with The Mezzanine Engine. If not, see <http://www.gnu.org/licenses/>.
16 */
17 /* The original authors have included a copy of the license specified above in the
18  'Docs' folder. See 'gpl.txt'
19 */
20 /* We welcome the use of the Mezzanine engine to anyone, including companies who wish to
21  Build professional software and charge for their product.
22 
23  However there are some practical restrictions, so if your project involves
24  any of the following you should contact us and we will try to work something
25  out:
26  - DRM or Copy Protection of any kind(except Copyrights)
27  - Software Patents You Do Not Wish to Freely License
28  - Any Kind of Linking to Non-GPL licensed Works
29  - Are Currently In Violation of Another Copyright Holder's GPL License
30  - If You want to change our code and not add a few hundred MB of stuff to
31  your distribution
32 
33  These and other limitations could cause serious legal problems if you ignore
34  them, so it is best to simply contact us or the Free Software Foundation, if
35  you have any questions.
36 
37  Joseph Toppi - toppij@gmail.com
38  John Blackwood - makoenergy02@gmail.com
39 */
40 #ifndef _stringtool_cpp
41 #define _stringtool_cpp
42 
43 #include "stringtool.h"
44 #include "exception.h"
45 
46 #include <sstream>
47 #include <algorithm>
48 #include <cctype>
49 //#include <locale>
50 
51 namespace
52 {
53  /// @internal
54  /// @brief Convenience multiplier used for converting a colour value for a single channel to a scalar value.
55  const Mezzanine::Real HexConversionMultiplier = Mezzanine::Real(1.0 / 255.0);
56 
57  /// @internal
58  /// @brief Converts a string containing hex to a ColourValue channel.
59  /// @param Hex The Hex value to be converted.
60  /// @return Returns a Real representing the converted Hex string that can be applied to a ColourValue channel.
61  Mezzanine::Real ConvertHexToColourChannel(const Mezzanine::String& Hex)
62  {
63  if( Hex.size() != 2 ) {
64  MEZZ_EXCEPTION(Mezzanine::Exception::PARAMETERS_EXCEPTION,"Hex code requires 2 characters to express a ColourValue channel.");
65  }
66 
67  Mezzanine::Real Ret = 0;
68  Mezzanine::StringStream Converter;
69  Converter << std::hex << Hex;
70  Converter >> Ret;
71  return std::min(Ret *= HexConversionMultiplier,Mezzanine::Real(1.0));
72  }
73  /// @internal
74  /// @brief Converts a ColourValue channel to Hex.
75  /// @param Channel The value to be converted to Hex.
76  /// @return Returns a two character string containing the hex expression for the provided channel value.
77  Mezzanine::String ConvertColourChannelToHex(const Mezzanine::Real Channel)
78  {
80  Mezzanine::StringStream Converter;
81  Converter << std::hex << static_cast<Mezzanine::UInt8>( Channel * 255.0 );
82  Converter >> Ret;
83 
84  if( Ret.size() == 1 ) {
85  Ret.insert(0,1,'0');
86  }
87  return Ret;
88  }
89 }
90 
91 namespace Mezzanine
92 {
93  ///////////////////////////////////////////////////////////////////////////////
94  // String Manipulation and checks
95 
96  void StringTools::Trim(String& Source, bool Left, bool Right)
97  {
98  static const String Delims = " \t\r";
99  if(Right)
100  Source.erase(Source.find_last_not_of(Delims)+1);
101  if(Left)
102  Source.erase(0,Source.find_first_not_of(Delims));
103  }
104 
105  CountedPtr<StringVector> StringTools::Split(const String& Source, const String& Delims, const Whole& MaxSplits)
106  {
108  Ret->reserve( MaxSplits ? MaxSplits+1 : 10 );
109  Whole Splits = 0;
110 
111  size_t Start = 0;
112  size_t Pos = 0;
113 
114  do
115  {
116  Pos = Source.find_first_of(Delims,Start);
117  if(Pos == Start)
118  {
119  Start = Pos + 1;
120  }
121  else if(Pos == String::npos || (MaxSplits && Splits == MaxSplits))
122  {
123  Ret->push_back(Source.substr(Start));
124  break;
125  }
126  else
127  {
128  Ret->push_back(Source.substr(Start,Pos - Start));
129  Start = Pos + 1;
130  }
131  Start = Source.find_first_not_of(Delims,Start);
132  ++Splits;
133  }while(Pos != String::npos);
134 
135  return Ret;
136  }
137 
139  {
140  std::transform(Source.begin(),Source.end(),Source.begin(),::toupper);
141  }
142 
144  {
145  std::transform(Source.begin(),Source.end(),Source.begin(),::tolower);
146  }
147 
148  bool StringTools::StartsWith(const String& Str, const String& Pattern, const bool CaseSensitive)
149  {
150  size_t StrLen = Str.length();
151  size_t PatternLen = Pattern.length();
152 
153  if(PatternLen > StrLen || PatternLen == 0)
154  return false;
155 
156  String Start = Str.substr(0,PatternLen);
157 
158  if(CaseSensitive)
159  {
160  String LowerPattern = Pattern;
161  ToLowerCase(Start);
162  ToLowerCase(LowerPattern);
163  return (Start == LowerPattern);
164  }
165 
166  return (Start == Pattern);
167  }
168 
169  bool StringTools::EndsWith(const String& Str, const String& Pattern, const bool CaseSensitive)
170  {
171  size_t StrLen = Str.length();
172  size_t PatternLen = Pattern.length();
173 
174  if(PatternLen > StrLen || PatternLen == 0)
175  return false;
176 
177  String End = Str.substr(StrLen - PatternLen,PatternLen);
178 
179  if(CaseSensitive)
180  {
181  String LowerPattern = Pattern;
182  ToLowerCase(End);
183  ToLowerCase(LowerPattern);
184  return (End == LowerPattern);
185  }
186 
187  return (End == Pattern);
188  }
189 
191  {
192  for( size_t CurrIndex = Source.find_first_of(" ") ; CurrIndex != String::npos ; CurrIndex = Source.find_first_of(" ",CurrIndex) )
193  {
194  size_t EndIndex = CurrIndex;
195  while( Source[EndIndex] == ' ' ) EndIndex++;
196  Source.replace(CurrIndex,EndIndex-CurrIndex," ");
197  CurrIndex++;
198  }
199  }
200 
201  ///////////////////////////////////////////////////////////////////////////////
202  // Data Class Utilities
203 
205  {
206  CountedPtr<StringVector> Digits = Split(ToConvert);
207  if(2 == Digits->size())
208  {
209  return Vector2(ConvertToReal(Digits->at(0)),ConvertToReal(Digits->at(1)));
210  }else{
211  MEZZ_EXCEPTION(Exception::PARAMETERS_EXCEPTION,"String does not contain 2 digits when attempting to convert.");
212  }
213  }
214 
216  {
217  std::stringstream converter;
218  converter << ToConvert.X << " " << ToConvert.Y;
219  return converter.str();
220  }
221 
223  {
224  CountedPtr<StringVector> Digits = Split(ToConvert);
225  if(3 == Digits->size())
226  {
227  return Vector3(ConvertToReal(Digits->at(0)),ConvertToReal(Digits->at(1)),ConvertToReal(Digits->at(2)));
228  }else{
229  MEZZ_EXCEPTION(Exception::PARAMETERS_EXCEPTION,"String does not contain 3 digits when attempting to convert.");
230  }
231  }
232 
234  {
235  std::stringstream converter;
236  converter << ToConvert.X << " " << ToConvert.Y << " " << ToConvert.Z;
237  return converter.str();
238  }
239 
241  {
242  CountedPtr<StringVector> Digits = Split(ToConvert);
243  if(4 == Digits->size())
244  {
245  return Quaternion(ConvertToReal(Digits->at(0)),ConvertToReal(Digits->at(1)),ConvertToReal(Digits->at(2)),ConvertToReal(Digits->at(3)));
246  }else{
247  MEZZ_EXCEPTION(Exception::PARAMETERS_EXCEPTION,"String does not contain 4 digits when attempting to convert.");
248  }
249  }
250 
252  {
253  std::stringstream converter;
254  converter << ToConvert.X << " " << ToConvert.Y << " " << ToConvert.Z << " " << ToConvert.W;
255  return converter.str();
256  }
257 
259  {
260  CountedPtr<StringVector> Digits = Split(ToConvert);
261  if(4 == Digits->size())
262  {
263  return ColourValue(ConvertToReal(Digits->at(0)),ConvertToReal(Digits->at(1)),ConvertToReal(Digits->at(2)),ConvertToReal(Digits->at(3)));
264  }else{
265  MEZZ_EXCEPTION(Exception::PARAMETERS_EXCEPTION,"String does not contain 4 digits when attempting to convert.");
266  }
267  }
268 
270  {
271  std::stringstream converter;
272  converter << ToConvert.RedChannel << " " << ToConvert.GreenChannel << " " << ToConvert.BlueChannel << " " << ToConvert.AlphaChannel;
273  return converter.str();
274  }
275 
277  {
278  if( ToConvert.size() < 6 ) {
279  MEZZ_EXCEPTION(Exception::PARAMETERS_EXCEPTION,"Hex code requires a minimum of 6 characters to express a ColourValue instance.");
280  }
281 
282  ColourValue Ret;
283  Ret.RedChannel = ConvertHexToColourChannel( ToConvert.substr(0,2) );
284  Ret.GreenChannel = ConvertHexToColourChannel( ToConvert.substr(2,2) );
285  Ret.BlueChannel = ConvertHexToColourChannel( ToConvert.substr(4,2) );
286 
287  if( ToConvert.size() == 6 ) Ret.AlphaChannel = 1.0;
288  else Ret.AlphaChannel = ConvertHexToColourChannel( ToConvert.substr(6,2) );
289 
290  return Ret;
291  }
292 
294  {
295  String Ret;
296  Ret.append( ConvertColourChannelToHex(ToConvert.RedChannel) );
297  Ret.append( ConvertColourChannelToHex(ToConvert.GreenChannel) );
298  Ret.append( ConvertColourChannelToHex(ToConvert.BlueChannel) );
299  Ret.append( ConvertColourChannelToHex(ToConvert.AlphaChannel) );
300  return Ret;
301  }
302 
303  ///////////////////////////////////////////////////////////////////////////////
304  // Convert-To-Data functions
305 
306  bool StringTools::ConvertToBool(const String& ToConvert, const bool Default)
307  {
308  String StrCopy = ToConvert;
309  StringTools::ToLowerCase(StrCopy);
310  if("true" == StrCopy) return true;
311  else if("yes" == StrCopy) return true;
312  else if("1" == StrCopy) return true;
313  else if("false" == StrCopy) return false;
314  else if("no" == StrCopy) return false;
315  else if("0" == StrCopy) return false;
316  else return Default;
317  }
318 
320  {
321  StringStream converter(ToConvert);
322  Real Result;
323  converter >> Result;
324  return Result;
325  }
326 
328  {
329  StringStream converter(ToConvert);
330  Integer Result;
331  converter >> Result;
332  return Result;
333  }
334 
336  {
337  StringStream converter(ToConvert);
338  Int8 Result;
339  converter >> Result;
340  return Result;
341  }
342 
344  {
345  StringStream converter(ToConvert);
346  UInt8 Result;
347  converter >> Result;
348  return Result;
349  }
350 
352  {
353  StringStream converter(ToConvert);
354  Int16 Result;
355  converter >> Result;
356  return Result;
357  }
358 
360  {
361  StringStream converter(ToConvert);
362  UInt16 Result;
363  converter >> Result;
364  return Result;
365  }
366 
368  {
369  StringStream converter(ToConvert);
370  Int32 Result;
371  converter >> Result;
372  return Result;
373  }
374 
376  {
377  StringStream converter(ToConvert);
378  UInt32 Result;
379  converter >> Result;
380  return Result;
381  }
382 
383  String StringTools::ConvertToString(const Input::InputCode& Code, bool ShiftPressed)
384  {
385  /// @todo Get this ( StringTools::ConvertToString ) to support non us keyboards
386  switch(Code)
387  {
388  case Input::KEY_A:
389  {
390  if(ShiftPressed) return "A";
391  else return "a";
392  break;
393  }
394  case Input::KEY_B:
395  {
396  if(ShiftPressed) return "B";
397  else return "b";
398  break;
399  }
400  case Input::KEY_C:
401  {
402  if(ShiftPressed) return "C";
403  else return "c";
404  break;
405  }
406  case Input::KEY_D:
407  {
408  if(ShiftPressed) return "D";
409  else return "d";
410  break;
411  }
412  case Input::KEY_E:
413  {
414  if(ShiftPressed) return "E";
415  else return "e";
416  break;
417  }
418  case Input::KEY_F:
419  {
420  if(ShiftPressed) return "F";
421  else return "f";
422  break;
423  }
424  case Input::KEY_G:
425  {
426  if(ShiftPressed) return "G";
427  else return "g";
428  break;
429  }
430  case Input::KEY_H:
431  {
432  if(ShiftPressed) return "H";
433  else return "h";
434  break;
435  }
436  case Input::KEY_I:
437  {
438  if(ShiftPressed) return "I";
439  else return "i";
440  break;
441  }
442  case Input::KEY_J:
443  {
444  if(ShiftPressed) return "J";
445  else return "j";
446  break;
447  }
448  case Input::KEY_K:
449  {
450  if(ShiftPressed) return "K";
451  else return "k";
452  break;
453  }
454  case Input::KEY_L:
455  {
456  if(ShiftPressed) return "L";
457  else return "l";
458  break;
459  }
460  case Input::KEY_M:
461  {
462  if(ShiftPressed) return "M";
463  else return "m";
464  break;
465  }
466  case Input::KEY_N:
467  {
468  if(ShiftPressed) return "N";
469  else return "n";
470  break;
471  }
472  case Input::KEY_O:
473  {
474  if(ShiftPressed) return "O";
475  else return "o";
476  break;
477  }
478  case Input::KEY_P:
479  {
480  if(ShiftPressed) return "P";
481  else return "p";
482  break;
483  }
484  case Input::KEY_Q:
485  {
486  if(ShiftPressed) return "Q";
487  else return "q";
488  break;
489  }
490  case Input::KEY_R:
491  {
492  if(ShiftPressed) return "R";
493  else return "r";
494  break;
495  }
496  case Input::KEY_S:
497  {
498  if(ShiftPressed) return "S";
499  else return "s";
500  break;
501  }
502  case Input::KEY_T:
503  {
504  if(ShiftPressed) return "T";
505  else return "t";
506  break;
507  }
508  case Input::KEY_U:
509  {
510  if(ShiftPressed) return "U";
511  else return "u";
512  break;
513  }
514  case Input::KEY_V:
515  {
516  if(ShiftPressed) return "V";
517  else return "v";
518  break;
519  }
520  case Input::KEY_W:
521  {
522  if(ShiftPressed) return "W";
523  else return "w";
524  break;
525  }
526  case Input::KEY_X:
527  {
528  if(ShiftPressed) return "X";
529  else return "x";
530  break;
531  }
532  case Input::KEY_Y:
533  {
534  if(ShiftPressed) return "Y";
535  else return "y";
536  break;
537  }
538  case Input::KEY_Z:
539  {
540  if(ShiftPressed) return "Z";
541  else return "z";
542  break;
543  }
544  case Input::KEY_1:
545  {
546  if(ShiftPressed) return "!";
547  else return "1";
548  break;
549  }
550  case Input::KEY_2:
551  {
552  if(ShiftPressed) return "@";
553  else return "2";
554  break;
555  }
556  case Input::KEY_3:
557  {
558  if(ShiftPressed) return "#";
559  else return "3";
560  break;
561  }
562  case Input::KEY_4:
563  {
564  if(ShiftPressed) return "$";
565  else return "4";
566  break;
567  }
568  case Input::KEY_5:
569  {
570  if(ShiftPressed) return "%";
571  else return "5";
572  break;
573  }
574  case Input::KEY_6:
575  {
576  if(ShiftPressed) return "^";
577  else return "6";
578  break;
579  }
580  case Input::KEY_7:
581  {
582  if(ShiftPressed) return "&";
583  else return "7";
584  break;
585  }
586  case Input::KEY_8:
587  {
588  if(ShiftPressed) return "*";
589  else return "8";
590  break;
591  }
592  case Input::KEY_9:
593  {
594  if(ShiftPressed) return "(";
595  else return "9";
596  break;
597  }
598  case Input::KEY_0:
599  {
600  if(ShiftPressed) return ")";
601  else return "0";
602  break;
603  }
604  case Input::KEY_MINUS:
605  {
606  if(ShiftPressed) return "_";
607  else return "-";
608  break;
609  }
610  case Input::KEY_EQUALS:
611  {
612  if(ShiftPressed) return "+";
613  else return "=";
614  break;
615  }
616  case Input::KEY_LEFTBRACKET:
617  {
618  if(ShiftPressed) return "{";
619  else return "[";
620  break;
621  }
622  case Input::KEY_RIGHTBRACKET:
623  {
624  if(ShiftPressed) return "}";
625  else return "]";
626  break;
627  }
629  {
630  if(ShiftPressed) return "\\";
631  else return "|";
632  break;
633  }
634  case Input::KEY_SEMICOLON:
635  {
636  if(ShiftPressed) return ":";
637  else return ";";
638  break;
639  }
640  case Input::KEY_APOSTROPHE:
641  {
642  if(ShiftPressed) return "\"";
643  else return "'";
644  break;
645  }
646  case Input::KEY_GRAVE:
647  {
648  if(ShiftPressed) return "~";
649  else return "`";
650  break;
651  }
652  case Input::KEY_COMMA:
653  {
654  if(ShiftPressed) return "<";
655  else return ",";
656  break;
657  }
658  case Input::KEY_PERIOD:
659  {
660  if(ShiftPressed) return ">";
661  else return ".";
662  break;
663  }
664  case Input::KEY_SLASH:
665  {
666  if(ShiftPressed) return "?";
667  else return "/";
668  break;
669  }
670  case Input::KEY_KP_1:
671  {
672  return "1";
673  break;
674  }
675  case Input::KEY_KP_2:
676  {
677  return "2";
678  break;
679  }
680  case Input::KEY_KP_3:
681  {
682  return "3";
683  break;
684  }
685  case Input::KEY_KP_4:
686  {
687  return "4";
688  break;
689  }
690  case Input::KEY_KP_5:
691  {
692  return "5";
693  break;
694  }
695  case Input::KEY_KP_6:
696  {
697  return "6";
698  break;
699  }
700  case Input::KEY_KP_7:
701  {
702  return "7";
703  break;
704  }
705  case Input::KEY_KP_8:
706  {
707  return "8";
708  break;
709  }
710  case Input::KEY_KP_9:
711  {
712  return "9";
713  break;
714  }
715  case Input::KEY_KP_0:
716  {
717  return "0";
718  break;
719  }
720  case Input::KEY_KP_PERIOD:
721  {
722  return ".";
723  break;
724  }
725  default:
726  return "";
727  break;
728  }
729  } // StringTools::ConvertToString
730 
731 
732 }//Mezzanine
733 
734 #endif