xmscore  1.0
StringUtil.cpp
Go to the documentation of this file.
1 //------------------------------------------------------------------------------
6 //------------------------------------------------------------------------------
7 
8 //----- Included files ---------------------------------------------------------
9 
10 // 1. Precompiled header
11 
12 // 2. My header
14 
15 // 3. Standard Library Headers
16 #include <cctype>
17 #include <cstdio>
18 #include <float.h>
19 
20 // 4. External Library Headers
21 #include <boost/algorithm/string.hpp>
22 #include <boost/algorithm/string/trim.hpp>
23 #include <boost/format.hpp>
24 #include <boost/lexical_cast.hpp>
25 
26 // 5. Shared Headers
27 #include <regex>
28 #include <xmscore/math/math.h>
29 #include <xmscore/misc/XmError.h>
30 
31 //#pragma warning(disable:4996) // 'strcpy': This function or variable may be
32 //unsafe.
33 
34 // 6. Non-shared Headers
35 
36 namespace xms {
42 //------------------------------------------------------------------------------
46 //------------------------------------------------------------------------------
48 #if defined(_MSC_VER) && _MSC_VER < 1900
49  m_oldOutputFormat = _get_output_format();
50  _set_output_format(_TWO_DIGIT_EXPONENT);
51 #elif defined(_MSC_VER) && _MSC_VER >= 1900
52 #pragma message("StTemp2DigitExponents class can be removed.")
53 #endif
54 } // StTemp2DigitExponents::StTemp2DigitExponents
55 //------------------------------------------------------------------------------
57 //------------------------------------------------------------------------------
59 #if defined(_MSC_VER) && _MSC_VER < 1900
60  _set_output_format(m_oldOutputFormat);
61 #endif
62 } // StTemp2DigitExponents::~StTemp2DigitExponents
63 
64 //------------------------------------------------------------------------------
69 //------------------------------------------------------------------------------
70 unsigned int stCountChar(const std::string &str, char c) {
71  unsigned int count = 0;
72  std::string::size_type size = str.size();
73 
74  for (std::string::size_type pos = 0; pos < size; ++pos) {
75  if (str[pos] == c) {
76  count++;
77  }
78  }
79 
80  return count;
81 } // stCountChar
82 //------------------------------------------------------------------------------
86 //------------------------------------------------------------------------------
87 bool stNumeric(const std::string &str) {
88  std::string copy(stTrimCopy(str));
89  std::stringstream ss(copy);
90  double temp;
91 
92  ss >> temp;
93 
94  return (!ss.fail() && ss.eof());
95 } // stNumeric
96 //------------------------------------------------------------------------------
102 //------------------------------------------------------------------------------
103 bool stScientificNotation(const std::string &str,
104  bool check_numeric /*= true*/) {
105  if (check_numeric && !stNumeric(str)) {
106  return false;
107  }
108 
109  return (str.find_first_of("eE") != std::string::npos);
110 } // stScientificNotation
111 //------------------------------------------------------------------------------
116 //------------------------------------------------------------------------------
117 void stChangeExtendedAscii(std::string &str, bool to_extended) {
118  const char *look_up[] = {// extended ASCII always goes first
119  // must be in pairs
120  "\xb2", "^2", // superscript two - squared
121  "\xb3", "^3", // superscript three - cubed
122  "\xb0",
123  "deg_", // degree sign
124  // this needs to be last and have both NULLs
125  nullptr, nullptr};
126 
127  unsigned int src = to_extended ? 1 : 0;
128  unsigned int dst = to_extended ? 0 : 1;
129 
130  for (; look_up[src] != nullptr; src += 2, dst += 2) {
131  stReplace(str, look_up[src], look_up[dst]);
132  }
133 } // stChangeExtendedAscii
134 //------------------------------------------------------------------------------
143 //------------------------------------------------------------------------------
144 VecStr stExplode(const std::string &source, const std::string &a_delimiter) {
145  std::string::size_type pos = source.find(a_delimiter);
146  std::vector<std::string> exploded;
147 
148  if (pos != std::string::npos) {
149  size_t delim_len = a_delimiter.size();
150 
151  exploded.push_back(source.substr(0, pos));
152 
153  while (pos != std::string::npos) {
154  std::string::size_type pos2 = source.find(a_delimiter, pos + 1);
155  std::string::size_type length = pos2 - pos - delim_len;
156 
157  if (pos2 == std::string::npos) {
158  length = std::string::npos;
159  }
160 
161  exploded.push_back(source.substr(pos + delim_len, length));
162 
163  pos = pos2;
164  }
165  } else {
166  if (!source.empty()) {
167  exploded.push_back(source);
168  }
169  }
170 
171  return exploded;
172 } // stExplode
173 //------------------------------------------------------------------------------
181 //------------------------------------------------------------------------------
182 VecStr stSplit(const std::string &a_source,
183  const std::string &a_delimiterList /*=wspace*/,
184  bool a_delimiterCompressOn /*true*/) {
185  std::string trimmed = stTrimCopy(a_source, a_delimiterList);
186  VecStr elems;
187  if (a_delimiterCompressOn) {
188  boost::split(elems, trimmed, boost::is_any_of(a_delimiterList),
189  boost::token_compress_on);
190  } else {
191  // Unfortunately, boost::token_compress_off doesn't do the trick because
192  // it still compresses the leading and trailing delimiters. The following
193  // code works. I don't know how fast it is.
194  std::vector<char> temp(a_source.size());
195  int end = 0;
196  for (size_t i = 0; i < a_source.size(); ++i) {
197  if (a_delimiterList.find(a_source[i]) != std::string::npos) {
198  elems.push_back(std::string(&temp[0], end));
199  end = 0;
200  } else {
201  temp[end++] = a_source[i];
202  }
203  }
204  if (a_delimiterList.find(a_source.back()) != std::string::npos) {
205  elems.push_back("");
206  }
207  }
208  return elems;
209 } // stSplit
210 //------------------------------------------------------------------------------
215 //------------------------------------------------------------------------------
216 std::string stImplode(const std::vector<std::string> &source,
217  const std::string &delim) {
218  std::string imploded;
219 
220  if (!source.empty()) {
221  size_t size = source.size() - 1;
222  for (size_t i = 0; i < size; ++i) {
223  imploded += source[i];
224  imploded += delim;
225  }
226 
227  imploded += source[size];
228  }
229 
230  return imploded;
231 } // stImplode
232 //------------------------------------------------------------------------------
238 //------------------------------------------------------------------------------
239 int stIndexOfElem(const VecStr &a_container, const std::string &str) {
240  int loc = 0;
241  for (int i = 0; i < static_cast<int>(a_container.size()); i++) {
242  if (a_container[i] == str) {
243  loc = i;
244  return loc;
245  }
246  }
247  loc = -1;
248  return loc;
249 } // indexOfElem
250 //------------------------------------------------------------------------------
257 //------------------------------------------------------------------------------
258 std::string stTrimCopy(const std::string &str,
259  const std::string &delim /*= wspace*/) {
260  std::string temp(str);
261 
262  return stTrim(temp, delim);
263 } // stTrimCopy
264 //------------------------------------------------------------------------------
269 //------------------------------------------------------------------------------
270 std::string &stTrimLeft(std::string &str,
271  const std::string &delim /*= wspace*/) {
272  std::string::size_type pos = str.find_first_not_of(delim);
273 
274  if (pos != std::string::npos) {
275  str.erase(0, pos);
276  } else {
277  str.clear();
278  }
279 
280  return str;
281 } // stTrimLeft
282 //------------------------------------------------------------------------------
287 //------------------------------------------------------------------------------
288 std::string &stTrimRight(std::string &str,
289  const std::string &delim /*= wspace*/) {
290  std::string::size_type pos = str.find_last_not_of(delim);
291 
292  if (pos != std::string::npos) {
293  str.erase(pos + 1);
294  } else {
295  str.clear();
296  }
297 
298  return str;
299 } // stTrimRight
300 //------------------------------------------------------------------------------
305 //------------------------------------------------------------------------------
306 std::string &stTrim(std::string &str, const std::string &delim /*= wspace*/) {
307  stTrimLeft(str, delim);
308  return stTrimRight(str, delim);
309 } // stTrim
310 //------------------------------------------------------------------------------
317 //------------------------------------------------------------------------------
318 std::string stReplaceCopy(const std::string &str, char source, char dest) {
319  std::string replaced(str);
320  stReplace(replaced, source, dest);
321  return replaced;
322 } // stReplaceCopy
323 //------------------------------------------------------------------------------
330 //------------------------------------------------------------------------------
331 std::string stReplaceCopy(const std::string &str, const std::string &source,
332  const std::string &dest) {
333  std::string replaced(str);
334  stReplace(replaced, source, dest);
335  return replaced;
336 } // stReplaceCopy
337 //------------------------------------------------------------------------------
344 //------------------------------------------------------------------------------
345 std::string &stReplace(std::string &str, char source, char dest) {
346  if (source == dest) {
347  return str;
348  }
349 
350  size_t pos = str.find(source);
351 
352  while (pos != std::string::npos) {
353  str[pos] = dest;
354  pos = str.find(source, pos + 1);
355  }
356 
357  return str;
358 } // stReplace
359 //------------------------------------------------------------------------------
366 //------------------------------------------------------------------------------
367 std::string &stReplace(std::string &str, const std::string &source,
368  const std::string &dest) {
369  if (source == dest) {
370  return str;
371  }
372 
373  std::string::size_type pos = str.find(source);
374  std::string::size_type source_len = source.size();
375  std::string::size_type dest_len = dest.size();
376 
377  while (pos != std::string::npos) {
378  str.erase(pos, source_len);
379  str.insert(pos, dest);
380  pos = str.find(source, pos + dest_len);
381  }
382 
383  return str;
384 } // stReplace
385 //------------------------------------------------------------------------------
391 //------------------------------------------------------------------------------
392 std::string stRemoveCopy(const std::string &str, char source) {
393  std::string copy(str);
394  return stRemove(copy, source);
395 } // stRemoveCopy
396 //------------------------------------------------------------------------------
402 //------------------------------------------------------------------------------
403 std::string &stRemove(std::string &str, char source) {
404  str.erase(std::remove(str.begin(), str.end(), source), str.end());
405  return str;
406 } // stRemove
407 //------------------------------------------------------------------------------
411 //------------------------------------------------------------------------------
412 std::string stToLowerCopy(const std::string &str) {
413  std::string copy(str);
414  return stToLower(copy);
415 } // stToLowerCopy
416 //------------------------------------------------------------------------------
420 //------------------------------------------------------------------------------
421 std::string &stToLower(std::string &str) {
422  std::transform<std::string::iterator, std::string::iterator, int (*)(int)>(
423  str.begin(), str.end(), str.begin(), std::tolower);
424 
425  return str;
426 } // stToLower
427 //------------------------------------------------------------------------------
431 //------------------------------------------------------------------------------
432 std::string stToUpperCopy(const std::string &str) {
433  std::string copy(str);
434  return stToUpper(copy);
435 } // stToUpperCopy
436 //------------------------------------------------------------------------------
440 //------------------------------------------------------------------------------
441 std::string &stToUpper(std::string &str) {
442  std::transform<std::string::iterator, std::string::iterator, int (*)(int)>(
443  str.begin(), str.end(), str.begin(), std::toupper);
444 
445  return str;
446 } // stToUpper
447 //------------------------------------------------------------------------------
451 //------------------------------------------------------------------------------
452 std::string stLeftCopy(const std::string &a_source, size_t const a_length) {
453  // make sure we didn't do signed int arithmetic to pass negative length that
454  // converts to very large unsigned number
455  XM_ASSERT(a_length == std::string::npos || a_length < (size_t)-1 - 1000);
456 
457  std::string copy(a_source);
458  return stLeft(copy, a_length);
459 } // stLeftCopy
460 //------------------------------------------------------------------------------
465 //------------------------------------------------------------------------------
466 std::string &stLeft(std::string &a_source, size_t const a_length) {
467  // make sure we didn't do signed int arithmetic to pass negative length that
468  // converts to very large unsigned number
469  XM_ASSERT(a_length == std::string::npos || a_length < (size_t)-1 - 1000);
470 
471  if (a_length == std::string::npos)
472  a_source = "";
473  else
474  a_source = a_source.substr(0, a_length);
475  return a_source;
476 } // stLeft
477 //------------------------------------------------------------------------------
483 //------------------------------------------------------------------------------
484 std::string stRightCopy(const std::string &a_source, size_t const a_length) {
485  // make sure we didn't do signed int arithmetic to pass negative length that
486  // converts to very large unsigned number
487  XM_ASSERT(a_length == std::string::npos || a_length < (size_t)-1 - 1000);
488 
489  std::string copy(a_source);
490  return stRight(copy, a_length);
491 } // stRightCopy
492 //------------------------------------------------------------------------------
496 //------------------------------------------------------------------------------
497 std::string stSimplified(const std::string &str) {
498  std::string modified = std::regex_replace(str, std::regex("\\s+"), " ");
499  modified = boost::trim_copy(modified);
500  return modified;
501 } // stSimplified
502 //------------------------------------------------------------------------------
508 //------------------------------------------------------------------------------
509 bool stContains(const std::string &a_container, const std::string &a_substr) {
510  std::string container = boost::to_upper_copy(a_container);
511  std::string substr = boost::to_upper_copy(a_substr);
512 
513  // return std::search(container.begin(), container.end(),
514  // substr.begin(), substr.end()) != container.end();
515 
516  if (container.find(substr) != std::string::npos)
517  return true;
518  return false;
519 
520 } // stContains
521 //------------------------------------------------------------------------------
526 //------------------------------------------------------------------------------
527 bool stVectorContainsString(const VecStr &a_container, const std::string &str) {
528  return (std::find(a_container.begin(), a_container.end(), str) !=
529  a_container.end());
530 } // stVectorContainsString
531 //------------------------------------------------------------------------------
536 //------------------------------------------------------------------------------
537 std::string &stRight(std::string &a_source, size_t const a_length) {
538  // make sure we didn't do signed int arithmetic to pass negative length that
539  // converts to very large unsigned number
540  XM_ASSERT(a_length == std::string::npos || a_length < (size_t)-1 - 1000);
541 
542  if (a_length >= a_source.size()) {
543  return a_source;
544  }
545  a_source = a_source.substr(a_source.size() - a_length);
546  return a_source;
547 } // stRight
548 //------------------------------------------------------------------------------
553 //------------------------------------------------------------------------------
554 bool stEqualNoCase(const std::string &a, const std::string &b) {
555  return boost::iequals(a, b);
556 } // stEqualNoCase
557 //------------------------------------------------------------------------------
562 //------------------------------------------------------------------------------
563 bool stFindNoCase(const std::string &a, const std::string &b) {
564  return stToLowerCopy(a).find(stToLowerCopy(b)) != std::string::npos;
565 } // stEqualNoCase
566 //------------------------------------------------------------------------------
571 //------------------------------------------------------------------------------
572 bool stMakeUnique(const std::set<std::string> &set_str, std::string &str) {
573  if (set_str.find(str) == set_str.end()) {
574  // the name is already unique
575  return false;
576  }
577 
578  std::string tmpstr;
579 
580  do {
581  std::string::size_type pos1, pos2;
582 
583  pos1 = str.find('(');
584  pos2 = str.find(')');
585 
586  if ((pos1 != std::string::npos) && (pos2 != std::string::npos) &&
587  (pos1 < pos2)) {
588  int old_val;
589  std::string::size_type diff;
590  std::stringstream ss;
591 
592  pos1++;
593 
594  diff = pos2 - pos1;
595 
596  ss.str(str.substr(pos1, diff));
597 
598  ss >> old_val;
599 
600  if (!ss.fail() && ss.eof()) {
601  ss.clear();
602  ss.str("");
603  ss << (old_val + 1);
604  str.replace(pos1, diff, ss.str(), 0, ss.str().length());
605  } else {
606  str += " (2)";
607  }
608  } else {
609  str += " (2)";
610  }
611  } while (set_str.find(str) != set_str.end());
612 
613  return true;
614 } // stMakeUnique
615 //------------------------------------------------------------------------------
624 //------------------------------------------------------------------------------
625 bool stStringToInt(const std::string &s, int &i, int base /*= 0*/) {
626  try {
627  size_t bad;
628  i = std::stoi(s, &bad, base);
629  if (bad < s.size()) {
630  return false;
631  }
632  } catch (std::exception) {
633  return false;
634  }
635  return true;
636 } // stStringToInt
637 //------------------------------------------------------------------------------
645 //------------------------------------------------------------------------------
646 bool stStringToDouble(const std::string &s, double &d) {
647  try {
648  size_t bad;
649  d = std::stod(s, &bad);
650  if (bad < s.size()) {
651  return false;
652  }
653  } catch (std::exception) {
654  return false;
655  }
656  return true;
657 } // stStringToDouble
658 //------------------------------------------------------------------------------
672 //------------------------------------------------------------------------------
673 int stPrecision(double value, int &flags, int length /* =15 */) {
674 #if BOOST_OS_WINDOWS
675  if (!_finite(value))
676 #else
677  if (!std::isfinite(value))
678 #endif
679  return 0;
680 
681  const int MAXFLOATDIGITS(7); // max sig figs available with single precision
682  const int MAXDOUBLEDIGITS(14); // max sig figs available with double precision
683 
684  double i; // integer part
685  double f; // fractional part
686  std::string istring;
687  std::string fstring;
688  std::string format;
689  size_t charptr;
690  int64_t ipart = 0;
691  short ilength, flength; // string lengths of integer and fractional parts
692  short prec; // ends up as num sig figs to right of decimal
693  short maxdigits; // max num digits to right of decimal to meet limit of 15
694  bool isFraction = false;
695 
696  // Step 1 ////////////////////////////////////////////////////////////////////
697 
698  /* First test if we need scientific notation for example
699  123456789012345
700 
701  -1000000000000.0 <- this number gets changed to...
702  -1.0000000e+012 <- this
703  -0.000001234567 <- this number gets changed to...
704  -1.2345678e-006 <- this
705  */
706 
707  if (length >= 8) { // Have to have at least 8 spaces to do sci notation
708  double max;
709  max = pow(10.0, (double)(length - 3));
710  const double min = 1e-5; // arbitrary value to use scientific notation below
711  // const double toleranceValueForZero = 1e-15; // arbitrary value to make
712  // values
713  // // below zero (perhaps should
714  // be
715  // // user defined in future)
716  // I'm returning this to the way it was because this change broke one of
717  // our tutorials in which 2e-17 is a valid input but this change made it
718  // impossible to enter that number and switched it to 0.0. I don't think
719  // we can impose an arbitrary value here in this macro that will be
720  // satisfactory to everyone in all cases. So, it should be done outside
721  // of this macro. Please don't change this without discussing it with
722  // everyone. -MJK
723  if (GT_EPS(fabs(value), max, DBL_EPSILON) ||
724  EQ_EPS(fabs(value), max, DBL_EPSILON) ||
725  //(GT_TOL(fabs(value), 0.0, toleranceValueForZero) &&
726  (GT_EPS(fabs(value), 0.0, DBL_EPSILON) &&
727  LT_EPS(fabs(value), min, DBL_EPSILON))) {
728  flags |= STR_SCIENTIFIC;
729  }
730  }
731 
732  // Step 2 ////////////////////////////////////////////////////////////////////
733 
734  /* Now find the number of sig figs there are to the right
735  of the decimal. The basic strategy is to
736  get a string from the number and count the characters that are sig
737  figs. There are different ways to get a string from the number and
738  we have tried and compared several in an attempt to get the best
739  results. The switch statement below has the different methods we've
740  tried. We keep the old stuff around because when we find that the
741  current thing isn't working for some case, we can look back and see
742  what we've already tried. */
743 
744  if (flags & STR_SCIENTIFIC) {
745  if (flags & STR_FLOAT)
746  istring = (boost::format("%1.6e") % value).str();
747  else
748  istring = (boost::format("%1.15e") % value).str();
749  fstring = istring;
750  charptr = istring.find('.');
751  istring = istring.substr(0, charptr);
752  charptr = fstring.find('.');
753  if (charptr != std::string::npos) {
754  charptr++;
755  fstring = fstring.substr(charptr);
756  }
757  charptr = fstring.find('e');
758  fstring = fstring.substr(0, charptr);
759  } else {
760  int myvar = 3;
761  std::string theval;
762  switch (myvar) {
763  case 1: // here we try getting all the digits we can and then formatting
764  // the string afterward
765 
766  {
767  // force the number into scientific and get all available valid digits
768  if (flags & STR_FLOAT)
769  theval = (boost::format("%1.6e") % value).str();
770  else
771  theval = (boost::format("%1.13e") % value).str();
772 
773  f = modf(value, &i);
774  ipart = boost::numeric_cast<int64_t>(i);
775  // get a string from the number
776  istring = (boost::format("%d") % ipart).str();
777  ilength = (short)istring.size();
778 
779  // remove the period from the string
780  stRemove(theval, '.');
781  // remove the integer part from the front of the string
782  theval.erase(0, ilength);
783  // delete the end of the string where 'e+004' is
784  size_t indx = theval.find("e");
785  theval.erase(indx, theval.size() - indx);
786  // copy what is left into fstring
787  fstring = theval;
788  } break;
789  case 2: {
790  f = modf(value, &i);
791  ipart = boost::numeric_cast<int64_t>(i);
792  istring = (boost::format("%d") % ipart).str();
793  // get a string from the number
794  fstring = (boost::format("%Lg") % f).str();
795  // Sometimes %g will use scientific notation, sometimes it won't. If it
796  // does, we've got to switch it to non-scientific notation.
797  if (fstring.find("e") != std::string::npos ||
798  fstring.find("E") != std::string::npos) {
799  double f2; // fractional part
800  f2 = std::stod(fstring);
801  fstring = (boost::format("%.16lf") % f2).str();
802  }
803  charptr = fstring.find('.');
804  if (charptr != std::string::npos) {
805  charptr++;
806  fstring = fstring.substr(charptr);
807  }
808  } break;
809  case 3: {
810  modf(value, &i);
811  ipart = boost::numeric_cast<int64_t>(i);
812  istring = (boost::format("%d") % ipart).str();
813  ilength = (short)istring.size();
814  if (ipart < 0)
815  ilength--;
816 
817  int maxDigits;
818  if (flags & STR_FLOAT)
819  maxDigits = MAXFLOATDIGITS;
820  else
821  maxDigits = MAXDOUBLEDIGITS;
822  if (ipart == 0 && value != 0.0) {
823  isFraction = true;
824  modf(log10(fabs(value)), &i);
825  int digits = maxDigits - Round(i);
826  if (value > 0.0)
827  ilength = (short)(digits + 2);
828  else
829  ilength = (short)(digits + 3);
830  format =
831  (boost::format("%s%d.%d%s") % "%" % ilength % digits % "f").str();
832  } else {
833  format = (boost::format("%s%d.%d%s") % "%" % ilength %
834  Miabs(maxDigits - ilength) % "f")
835  .str();
836  }
837 
838  fstring = (boost::format(format) % value).str();
839 
840  charptr = fstring.find('.');
841  if (charptr != std::string::npos) {
842  charptr++;
843  fstring = fstring.substr(charptr);
844  }
845  } break;
846  }
847  }
848  ilength = (short)istring.size();
849  flength = (short)fstring.size();
850 
851  /* "Only about 7 decimal digits are representable in single-precision IEEE
852  format, and about 16 in double-precision IEEE format" (The Perils of
853  Floating-Point). So subtract ilength (the length of the left side) from
854  7 or 16 and see how many are left over on the right. Start from that
855  point and work left, skipping zeros until we hit a non-zero number. */
856  if (value < 0) {
857  ilength--; /* don't count the - sign as a sig fig. */
858  }
859  if (isFraction)
860  prec = flength;
861  else if (flags & STR_FLOAT) {
862  prec = MAXFLOATDIGITS - ilength - 1;
863  } else {
864  prec = MAXDOUBLEDIGITS - ilength - 1;
865  }
866  if (ilength == 1 && ipart == 0) {
867  prec++; // 0 on left of 0.1 isn't a sig fig, one more avail for right
868  }
869  if (prec >= flength) {
870  prec = flength - 1; // just in case we screwed up some how
871  }
872  for (; prec >= 0; prec--) {
873  if (fstring.at(prec) != '0')
874  break;
875  }
876  prec++;
877  // At this point prec is number of sig figs to the right of the decimal
878 
879  // Step 3 ////////////////////////////////////////////////////////////////////
880 
881  /* Find the max number of digits to the right of the decimal we can allow,
882  based on a total number of <length> digits including the '-' and the '.'
883  This is necessary because we might get round off errors above causing
884  garbage values towards the end of the string causing prec to be more
885  than it should be. Here's an example if <length> is 15. */
886 
887  /* 123456789012345 123456789012345 maxdigits */
888  /* fabs(value) >= fabs(-100000000000.0) 1 */
889  /* fabs(-100000000000.0) > fabs(value) >= fabs(-10000000000.00) 2 */
890  /* fabs(-10000000000.00) > fabs(value) >= fabs(-1000000000.000) 3 */
891  /* fabs(-1000000000.000) > fabs(value) >= fabs(-100000000.0000) 4 */
892  /* fabs(-100000000.0000) > fabs(value) >= fabs(-10000000.00000) 5 */
893  /* fabs(-10000000.00000) > fabs(value) >= fabs(-1000000.000000) 6 */
894  /* fabs(-1000000.000000) > fabs(value) >= fabs(-100000.0000000) 7 */
895  /* fabs(-100000.0000000) > fabs(value) >= fabs(-10000.00000000) 8 */
896  /* fabs(-10000.00000000) > fabs(value) >= fabs(-1000.000000000) 9 */
897  /* fabs(-1000.000000000) > fabs(value) >= fabs(-100.0000000000) 10 */
898  /* fabs(-100.0000000000) > fabs(value) >= fabs(-10.00000000000) 11 */
899  /* fabs(-10.00000000000) > fabs(value) >= fabs(-1.000000000000) 12 */
900  /* fabs(-1.000000000000) > fabs(value) >= fabs(-.1000000000000) 12 */
901  /* fabs(-.1000000000000) > fabs(value) >= fabs(-.0100000000000) 12 */
902 
903  if (flags & STR_SCIENTIFIC) {
904  maxdigits = (short)(length - 8); // 8 places used for -1. and e+012
905  } else {
906  maxdigits =
907  (short)(length - 3); // 3 because 1 for + or -, 1 for 0, 1 for . (-0.)
908  double testval;
909  testval = 10.0;
910  if (!LT_EPS(fabs(value), testval, DBL_EPSILON)) {
911  do {
912  maxdigits--;
913  testval *= 10.0;
914  } while (!LT_EPS(fabs(value), testval, DBL_EPSILON));
915  }
916  }
917  if (!(value < 0.0)) {
918  maxdigits++; // If value is positive, you get one more
919  }
920 
921  // Step 4 ////////////////////////////////////////////////////////////////////
922 
923  // Compare the maximum number of significant digits to the right of the
924  // decimal allowed <maxdigits> with how many we have <prec>. If we have
925  // more than we're allowed, we have to throw out the extra. If we have
926  // to throw some out, we have to see if the ones we have left are
927  // still significant - if the ones on the right are 0, then they're no
928  // longer significant.
929 
930  if (prec > maxdigits) {
931  prec = maxdigits;
932  // format = (boost::format("%s%d.%d%s") % "%" % ilength % prec % "f").str();
933  // fstring = (boost::format(format) % value).str();
934  // charptr = fstring.find('.');
935  // if (charptr != std::string::npos) {
936  // charptr++;
937  // fstring = fstring.substr(charptr);
938  //}
939  if ((int)fstring.size() > prec && fstring.at(prec - 1) == '0') {
940  std::stringstream ss;
941  ss << fstring.at(prec);
942  int val;
943  ss >> val;
944  if (val > 4)
945  fstring.at(prec - 1) = '1';
946  }
947  for (; prec >= 1; prec--) {
948  if (fstring.at(prec - 1) != '0') {
949  break;
950  }
951  }
952  }
953  if (prec < 1) {
954  prec = 1; // always show 5.0 instead of just 5 to indicate it's a float
955  }
956 
957  return prec;
958 } // stPrecision
959 //------------------------------------------------------------------------------
994 //------------------------------------------------------------------------------
995 std::string STRstd(double a_value, int a_n /*=-1*/, int width /*=15*/,
996  int flags /*=0*/) {
997  std::string str;
998  int prec = 0;
999 
1000  // put this check in for old stuff
1001  if (a_n >= 800) {
1002  XM_ASSERT(false);
1003  a_n = -1;
1004  }
1005 
1006  // check for invalid values
1007 #if BOOST_OS_WINDOWS
1008  if (!_finite(a_value)) {
1009  switch (_fpclass(a_value)) {
1010  case _FPCLASS_NINF:
1011  str = "-INF";
1012  break;
1013  case _FPCLASS_PINF:
1014  str = "+INF";
1015  break;
1016  default:
1017  str = "NaN";
1018  break;
1019  }
1020  return str;
1021  }
1022 #else
1023  if (!std::isfinite(a_value)) {
1024  switch (std::fpclassify(a_value)) {
1025  case FP_INFINITE:
1026  if (std::signbit(a_value))
1027  str = "-INF";
1028  else
1029  str = "+INF";
1030  break;
1031  default:
1032  str = "NaN";
1033  break;
1034  }
1035  return str;
1036  }
1037 #endif
1038 
1039  // if not specifying an exact prec, autocompute
1040  if ((a_n == -1) || (flags & STR_USEMAXPREC)) {
1041  // if using max precision and the number is small, truncate the number to
1042  // max precision here before stPrecision() switches the number to scientific
1043  // notation (a number that is beyond the limited precision range)
1044  if ((flags & STR_USEMAXPREC) && LT_TOL(fabs(a_value), 1e-4, DBL_EPSILON)) {
1045  a_value *= pow(10.0, a_n);
1046  a_value = floor(a_value + 0.5);
1047  a_value /= pow(10.0, a_n);
1048  }
1049  // figure out the auto-computed prec is
1050  try {
1051  prec = stPrecision(a_value, flags, width);
1052  } catch (std::exception &) {
1053  // we had an error. Generally with casting the modf integer part
1054  // return "";
1055  prec = 2; // Try 2. Probably better than returning ""
1056  }
1057  if ((flags & STR_USEMAXPREC) && prec > a_n) {
1058  prec = a_n;
1059  }
1060  } else {
1061  prec = a_n;
1062  }
1063 
1064  // Format the format string, then use it to format str
1065 
1066  std::string format;
1067  if (flags & STR_SCIENTIFIC) {
1068  // sprintf(format, "%%.%de", Miabs(prec));
1069  format = (boost::format("%%.%de") % Miabs(prec)).str();
1070  } else {
1071  // sprintf(format, "%%.%dlf", prec);
1072  // I added Miabs because according to my book it must be nonnegative
1073  // and some combinations result in a negative prec, which crashes. -MJK
1074  format = (boost::format("%%.%dlf") % Miabs(prec)).str();
1075  }
1076 
1077  if (!(flags & STR_WITHCOMMAS)) {
1078  // str.Format(format, a_value);
1079  str = (boost::format(format) % a_value).str();
1080  } else {
1081  // Use the system locale to get the commas (or whatever else)
1082  std::locale loc(""); // system locale
1083  str = (boost::format(format, loc) % a_value).str();
1084  }
1085 
1086  // in some cases when specifying max prec, trailing zeros can occur. For
1087  // example, if the number is 5.0003 and the maxprec is 3, the string right
1088  // here will be 5.000 instead of 5.0.
1089  if ((a_n == -1) || (flags & STR_USEMAXPREC)) {
1090  // see if there's a decimal point
1091  size_t index = str.find('.');
1092  if (index != std::string::npos) {
1093  if ((index = str.find_first_of("eE")) != std::string::npos) {
1094  // Scientific. Start at 'e' or 'E' and go left, removing zeros
1095  index--;
1096  while (index > 0 && str.at(index) == '0' && str.at(index - 1) != '.') {
1097  str.erase(index, 1);
1098  index--;
1099  }
1100  } else {
1101  // take off any trailing zeros
1102  stTrimRight(str, "0");
1103  // make sure there's at least one zero
1104  if (str[str.size() - 1] == '.') {
1105  str += '0';
1106  }
1107  }
1108  }
1109  }
1110 
1111  // in some cases you want the string to always be a certain number of
1112  // character. This is most common with FORTRASH fixed format garbage.
1113  if (flags & STR_FULLWIDTH) {
1114  int len = (int)str.size();
1115  int diff = width - len;
1116  if (diff > 0) {
1117  std::string str1, str2;
1118  for (size_t i = 0; i < diff; i++)
1119  str1 += " ";
1120  str2 = str;
1121  str = str1 + str2;
1122  }
1123  }
1124 
1125  // if the string is "-0.0" remove the negative sign
1126  if (str == "-0.0") {
1127  str = "0.0";
1128  }
1129 
1130  return str;
1131 } // STRstd
1132 //----- OVERLOAD ---------------------------------------------------------------
1167 //----- OVERLOAD ---------------------------------------------------------------
1168 std::string STRstd(float value, int n /*=-1*/, int width /*=15*/,
1169  int flags /*=0*/) {
1170  return STRstd((double)value, n, width, flags);
1171 } // STRstd
1172 //----- OVERLOAD ---------------------------------------------------------------
1177 //----- OVERLOAD ---------------------------------------------------------------
1178 std::string STRstd(std::string value) { return value; }
1179 
1185 //------------------------------------------------------------------------------
1188 //------------------------------------------------------------------------------
1190  return ',';
1191 } // StCommaNumpunct::do_thousands_sep
1192 //------------------------------------------------------------------------------
1195 //------------------------------------------------------------------------------
1196 std::string StCommaNumpunct::do_grouping() const {
1197  return "\03";
1198 } // StCommaNumpunct::do_grouping
1199 
1200 } // end namespace xms
1201 
1202 //#if 0
1203 #ifdef CXX_TEST
1204 
1205 #include <xmscore/misc/StringUtil.t.h>
1206 
1207 #include <xmscore/stl/vector.h>
1208 #include <xmscore/testing/TestTools.h>
1209 
1210 //----- Namespace declaration --------------------------------------------------
1211 
1212 namespace {
1213 
1214 struct ValStr {
1215  double val;
1216  int n;
1217  int width;
1218  int flag;
1219  std::string str;
1220 };
1221 
1222 //----- Internal functions -----------------------------------------------------
1223 
1224 //------------------------------------------------------------------------------
1226 //------------------------------------------------------------------------------
1227 void GetVectorsFromArray(std::vector<ValStr> a_array, xms::VecDbl &a_vals,
1228  xms::VecInt &a_ns, xms::VecInt &a_widths,
1229  xms::VecInt &a_flags, xms::VecStr &a_strs) {
1230  a_vals.clear();
1231  a_ns.clear();
1232  a_widths.clear();
1233  a_flags.clear();
1234  a_strs.clear();
1235  for (int i = 0; i < a_array.size(); ++i) {
1236  a_vals.push_back(a_array[i].val);
1237  a_ns.push_back(a_array[i].n);
1238  a_widths.push_back(a_array[i].width);
1239  a_flags.push_back(a_array[i].flag);
1240  a_strs.push_back(a_array[i].str);
1241  }
1242 } // GetVectorsFromArray
1243 //------------------------------------------------------------------------------
1245 //------------------------------------------------------------------------------
1246 void RunPrec(const xms::VecDbl &a_values, const xms::VecInt &a_flags,
1247  const xms::VecInt &a_precs) {
1248  TS_ASSERT_EQUALS(a_values.size(), a_flags.size());
1249  TS_ASSERT_EQUALS(a_values.size(), a_precs.size());
1250 
1251  // Create the "observed answer" vectors
1252  xms::VecInt flags(a_values.size(), 0);
1253  xms::VecInt precs(a_values.size(), 0);
1254 
1255  for (int i = 0; i < (int)a_values.size(); ++i) {
1256  precs.at(i) = xms::stPrecision(a_values.at(i), flags.at(i));
1257  }
1258  TS_ASSERT_EQUALS_VEC(flags, a_flags);
1259  TS_ASSERT_EQUALS_VEC(precs, a_precs);
1260 } // RunPrec
1261 //------------------------------------------------------------------------------
1263 //------------------------------------------------------------------------------
1264 void RunSTR(const xms::VecDbl &a_vals, const xms::VecInt &a_ns,
1265  const xms::VecInt &a_widths, const xms::VecInt &a_flags,
1266  const xms::VecStr &a_strs) {
1267  TS_ASSERT_EQUALS(a_vals.size(), a_ns.size());
1268  TS_ASSERT_EQUALS(a_vals.size(), a_widths.size());
1269  TS_ASSERT_EQUALS(a_vals.size(), a_flags.size());
1270  TS_ASSERT_EQUALS(a_vals.size(), a_strs.size());
1271 
1272  // Create the "observed answer" vector
1273  xms::VecStr strs(a_vals.size(), "");
1274 
1275  for (int i = 0; i < (int)a_vals.size(); ++i) {
1276  strs.at(i) =
1277  xms::STRstd(a_vals.at(i), a_ns.at(i), a_widths.at(i), a_flags.at(i));
1278  }
1279  TS_ASSERT_EQUALS_VEC(strs, a_strs);
1280 } // RunSTR
1281 } // unnamed namespace
1282 
1287 //------------------------------------------------------------------------------
1289 //------------------------------------------------------------------------------
1291  // \xb2 superscript two - squared
1292  // \xb3 superscript three - cubed
1293  // \xb0 degree sign
1294  std::string str1("test\xb2");
1295  std::string str2("test\xb3");
1296  std::string str3("\xb0test");
1297 
1298  xms::stChangeExtendedAscii(str1, false);
1299  xms::stChangeExtendedAscii(str2, false);
1300  xms::stChangeExtendedAscii(str3, false);
1301 
1302  TS_ASSERT_EQUALS("test^2", str1);
1303  TS_ASSERT_EQUALS("test^3", str2);
1304  TS_ASSERT_EQUALS("deg_test", str3);
1305 
1306  xms::stChangeExtendedAscii(str1, true);
1307  xms::stChangeExtendedAscii(str2, true);
1308  xms::stChangeExtendedAscii(str3, true);
1309 
1310  TS_ASSERT_EQUALS("test\xb2", str1);
1311  TS_ASSERT_EQUALS("test\xb3", str2);
1312  TS_ASSERT_EQUALS("\xb0test", str3);
1313 } // StringUtilUnitTests::testExtendedASCII
1314 //------------------------------------------------------------------------------
1316 //------------------------------------------------------------------------------
1318  std::vector<std::string> values;
1319 
1320  values.push_back("test");
1321  values.push_back("test2");
1322  values.push_back("test3");
1323  values.push_back("test4");
1324 
1325  std::string result = xms::stImplode(values, "stuff");
1326 
1327  TS_ASSERT_EQUALS("teststufftest2stufftest3stufftest4", result);
1328 
1329  std::vector<std::string> result2;
1330  result2 = xms::stExplode(result, "stuff");
1331  TS_ASSERT_EQUALS_VEC(values, result2);
1332 
1333  values.clear();
1334  result = xms::stImplode(values, "stuff");
1335  TS_ASSERT_EQUALS("", result);
1336 
1337  result2 = xms::stExplode(result, "stuff");
1338  TS_ASSERT_EQUALS_VEC(values, result2);
1339 
1340  values.push_back("test");
1341  result = xms::stImplode(values, "stuff");
1342  TS_ASSERT_EQUALS("test", result);
1343 
1344  result2 = xms::stExplode(result, "stuff");
1345  TS_ASSERT_EQUALS_VEC(values, result2);
1346 
1347  result = xms::stImplode(values, " "); // test test2 test3 test4
1348  result2 = xms::stExplode(result, " ");
1349  std::vector<std::string> expected = {"test", "test2", "test3", "test4"};
1350  // TS_ASSERT_EQUALS_VEC(expected, result2); // FAIL!
1351 
1352 } // StringUtilUnitTests::testImplodeExplode
1353 //------------------------------------------------------------------------------
1355 //------------------------------------------------------------------------------
1357  int expected = -1;
1358  xms::VecStr container = {"me", "you", "they", "we", "Us"};
1359  int test1 = xms::stIndexOfElem(container, "us"); // this should return -1
1360  TS_ASSERT_EQUALS(expected, test1);
1361 
1362  expected = 2;
1363  int test2 = xms::stIndexOfElem(container, "they"); // this should return 2
1364  TS_ASSERT_EQUALS(expected, test2);
1365 } // StringUtilUnitTests::testSuIndexOfElem
1366 //------------------------------------------------------------------------------
1368 //------------------------------------------------------------------------------
1370  std::string s = " 1 2 3\t4\t\t5 \t6 ";
1371  std::vector<std::string> expected;
1372  std::vector<std::string> r;
1373 
1374  r = xms::stSplit(s);
1375  expected = {"1", "2", "3", "4", "5", "6"};
1376  TS_ASSERT_EQUALS_VEC(expected, r);
1377 
1378  r = xms::stSplit(s, " ");
1379  expected = {"1", "2", "3\t4\t\t5", "\t6"};
1380  TS_ASSERT_EQUALS_VEC(expected, r);
1381 
1382  r = xms::stSplit(s, "\t");
1383  expected = {" 1 2 3", "4", "5 ", "6 "};
1384  TS_ASSERT_EQUALS_VEC(expected, r);
1385 
1386  r = xms::stSplit(s, " \t");
1387  expected = {"1", "2", "3", "4", "5", "6"};
1388  TS_ASSERT_EQUALS_VEC(expected, r);
1389 
1390  r = xms::stSplit(",,A,B,,C,,,", ",", false);
1391  expected = {"", "", "A", "B", "", "C", "", "", ""};
1392  TS_ASSERT_EQUALS_VEC(expected, r);
1393 } // StringUtilUnitTests::testSplit
1394 //------------------------------------------------------------------------------
1396 //------------------------------------------------------------------------------
1398  const std::string expected1("make");
1399  const std::string expected2("make (2)");
1400  const std::string expected3("make (10)");
1401 
1402  std::set<std::string> set_str;
1403  std::string str("make");
1404 
1405  set_str.insert("test");
1406  set_str.insert("stuff");
1407  set_str.insert("yup");
1408 
1409  TS_ASSERT(!xms::stMakeUnique(set_str, str));
1410  TS_ASSERT_EQUALS(expected1, str);
1411 
1412  set_str.insert("make");
1413  set_str.insert("make (3)");
1414 
1415  TS_ASSERT(xms::stMakeUnique(set_str, str));
1416  TS_ASSERT_EQUALS(expected2, str);
1417 
1418  set_str.insert("make (2)");
1419  set_str.insert("make (4)");
1420  set_str.insert("make (5)");
1421  set_str.insert("make (6)");
1422  set_str.insert("make (7)");
1423  set_str.insert("make (8)");
1424  set_str.insert("make (9)");
1425 
1426  TS_ASSERT(xms::stMakeUnique(set_str, str));
1427  TS_ASSERT_EQUALS(expected3, str);
1428 } // StringUtilUnitTests::testMakeUnique
1429 //------------------------------------------------------------------------------
1431 //------------------------------------------------------------------------------
1433  // TS_FAIL("StringUtilUnitTests::testTrim");
1434  {
1435  std::string test("\f this has white space\t \n \r \v");
1436  xms::stTrim(test);
1437  TS_ASSERT_EQUALS("this has white space", test);
1438  }
1439  {
1440  std::string test(" ");
1441  xms::stTrim(test);
1442  // Is this how it should work?
1443  // TS_ASSERT_EQUALS(" ", test);
1444  // No. Fixed to match how CString::Trim works 5/29/2015 by MJK.
1445  TS_ASSERT_EQUALS("", test);
1446  }
1447  {
1448  std::string test(" , * ");
1449  xms::stTrim(test, " ,*");
1450  TS_ASSERT_EQUALS("", test);
1451  }
1452 } // StringUtilUnitTests::testTrim
1453 //------------------------------------------------------------------------------
1455 //------------------------------------------------------------------------------
1457  std::string test("this has a few spaces");
1458 
1459  xms::stReplace(test, ' ', '_');
1460  TS_ASSERT_EQUALS("this_has_a_few_spaces", test);
1461 
1462  std::string test_copy(xms::stReplaceCopy(test, '_', ' '));
1463  TS_ASSERT_EQUALS("this has a few spaces", test_copy);
1464  TS_ASSERT_EQUALS("this_has_a_few_spaces", test);
1465 
1466  xms::stReplace(test, "a_few", "zero");
1467  TS_ASSERT_EQUALS("this_has_zero_spaces", test);
1468 
1469  xms::stReplace(test, "_", ""); // Replace spaces with nothing
1470  TS_ASSERT_EQUALS("thishaszerospaces", test);
1471 } // StringUtilUnitTests::testReplace
1472 //------------------------------------------------------------------------------
1474 //------------------------------------------------------------------------------
1476  std::string test("how much wood would a woodchuck chuck if a woodchuck could"
1477  " chuck wood?");
1478 
1479  TS_ASSERT_EQUALS(11, xms::stCountChar(test, 'o'));
1480 } // StringUtilUnitTests::testCountChar
1481 //------------------------------------------------------------------------------
1483 //------------------------------------------------------------------------------
1485  std::string test("-123e+201");
1486 
1487  TS_ASSERT(xms::stNumeric(test));
1488  TS_ASSERT(xms::stScientificNotation(test));
1489 
1490  test = "42";
1491 
1492  TS_ASSERT(xms::stNumeric(test));
1493  TS_ASSERT(!xms::stScientificNotation(test));
1494 
1495  test = "muffin monster";
1496 
1497  TS_ASSERT(!xms::stNumeric(test));
1498  TS_ASSERT(!xms::stScientificNotation(test));
1499  // This is why you don't pass false unless you are sure you have a number.
1500  // It will pass if it finds an e or E. This is for speeding up if you create
1501  // a stNumeric string and want to see if it went to scientific notation.
1502  TS_ASSERT(xms::stScientificNotation(test, false));
1503 } // StringUtilUnitTests::testNumAndSciNot
1504 //------------------------------------------------------------------------------
1506 //------------------------------------------------------------------------------
1508  std::string str("aBcD");
1509  TS_ASSERT_EQUALS("ABCD", xms::stToUpper(str));
1510 
1511  const std::string str_const("aBcD");
1512  // TS_ASSERT_EQUALS("ABCD", xms::stToUpper(str_const));
1513  // The above doesn't compile. You have to use stToUpperCopy with a const
1514  TS_ASSERT_EQUALS("ABCD", xms::stToUpperCopy(str_const));
1515 
1516 } // StringUtilUnitTests::testToUpper
1517 //------------------------------------------------------------------------------
1519 //------------------------------------------------------------------------------
1521  // TS_FAIL("StringUtilUnitTests::test_str2int");
1522 
1523  std::string str;
1524  const int TEST_NONE = -1;
1525  int i = TEST_NONE;
1526  bool rv;
1527 
1528  str = "";
1529  i = TEST_NONE;
1530  rv = xms::stStringToInt(str, i);
1531  TS_ASSERT_EQUALS(i, TEST_NONE);
1532  TS_ASSERT_EQUALS(rv, false);
1533 
1534  str = "aBcD";
1535  i = TEST_NONE;
1536  rv = xms::stStringToInt(str, i);
1537  TS_ASSERT_EQUALS(i, TEST_NONE);
1538  TS_ASSERT_EQUALS(rv, false);
1539 
1540  str = "1aBcD";
1541  i = TEST_NONE;
1542  rv = xms::stStringToInt(str, i);
1543  TS_ASSERT_EQUALS(i, 1);
1544  TS_ASSERT_EQUALS(rv, false);
1545 
1546  str = "1";
1547  i = TEST_NONE;
1548  rv = xms::stStringToInt(str, i);
1549  TS_ASSERT_EQUALS(i, 1);
1550  TS_ASSERT_EQUALS(rv, true);
1551 
1552  str = "-1";
1553  i = TEST_NONE;
1554  rv = xms::stStringToInt(str, i);
1555  TS_ASSERT_EQUALS(i, -1);
1556  TS_ASSERT_EQUALS(rv, true);
1557 
1558  str = "0";
1559  i = TEST_NONE;
1560  rv = xms::stStringToInt(str, i);
1561  TS_ASSERT_EQUALS(i, 0);
1562  TS_ASSERT_EQUALS(rv, true);
1563 
1564  str = "1.0";
1565  i = TEST_NONE;
1566  rv = xms::stStringToInt(str, i);
1567  TS_ASSERT_EQUALS(i, 1);
1568  TS_ASSERT_EQUALS(rv, false);
1569 
1570  str = "1.5";
1571  i = TEST_NONE;
1572  rv = xms::stStringToInt(str, i);
1573  TS_ASSERT_EQUALS(i, 1);
1574  TS_ASSERT_EQUALS(rv, false);
1575 
1576 } // StringUtilUnitTests::testToUpper
1577 //------------------------------------------------------------------------------
1579 //------------------------------------------------------------------------------
1581  // TS_FAIL("StringUtilUnitTests::testMisc");
1582 
1583  std::string s1 = "abcdefg";
1584  const std::string s2 = s1;
1585  std::string s3;
1586 
1587  // stLeft
1588 
1589  xms::stLeft(s1, 0);
1590  TS_ASSERT_EQUALS("", s1);
1591  s1 = s2;
1592  xms::stLeft(s1, 1);
1593  TS_ASSERT_EQUALS("a", s1);
1594  s1 = s2;
1595  xms::stLeft(s1, 2);
1596  TS_ASSERT_EQUALS("ab", s1);
1597  s1 = s2;
1598  xms::stLeft(s1, 7);
1599  TS_ASSERT_EQUALS("abcdefg", s1);
1600  s1 = s2;
1601  xms::stLeft(s1, 8);
1602  TS_ASSERT_EQUALS("abcdefg", s1);
1603  s1 = s2;
1604 
1605  // stLeftCopy
1606 
1607  s3 = xms::stLeftCopy(s2, 0);
1608  TS_ASSERT_EQUALS("abcdefg", s2);
1609  TS_ASSERT_EQUALS("", s3);
1610  s3 = xms::stLeftCopy(s2, 1);
1611  TS_ASSERT_EQUALS("abcdefg", s2);
1612  TS_ASSERT_EQUALS("a", s3);
1613  s3 = xms::stLeftCopy(s2, 2);
1614  TS_ASSERT_EQUALS("abcdefg", s2);
1615  TS_ASSERT_EQUALS("ab", s3);
1616  s3 = xms::stLeftCopy(s2, 7);
1617  TS_ASSERT_EQUALS("abcdefg", s2);
1618  TS_ASSERT_EQUALS("abcdefg", s3);
1619  s3 = xms::stLeftCopy(s2, 8);
1620  TS_ASSERT_EQUALS("abcdefg", s2);
1621  TS_ASSERT_EQUALS("abcdefg", s3);
1622 
1623  // stRight
1624 
1625  xms::stRight(s1, 0);
1626  TS_ASSERT_EQUALS("", s1);
1627  s1 = s2;
1628  xms::stRight(s1, 1);
1629  TS_ASSERT_EQUALS("g", s1);
1630  s1 = s2;
1631  xms::stRight(s1, 2);
1632  TS_ASSERT_EQUALS("fg", s1);
1633  s1 = s2;
1634  xms::stRight(s1, 7);
1635  TS_ASSERT_EQUALS("abcdefg", s1);
1636  s1 = s2;
1637  xms::stRight(s1, 8);
1638  TS_ASSERT_EQUALS("abcdefg", s1);
1639  s1 = s2;
1640 
1641  // stRightCopy
1642 
1643  s3 = xms::stRightCopy(s2, 0);
1644  TS_ASSERT_EQUALS("abcdefg", s2);
1645  TS_ASSERT_EQUALS("", s3);
1646  s3 = xms::stRightCopy(s2, 1);
1647  TS_ASSERT_EQUALS("abcdefg", s2);
1648  TS_ASSERT_EQUALS("g", s3);
1649  s3 = xms::stRightCopy(s2, 2);
1650  TS_ASSERT_EQUALS("abcdefg", s2);
1651  TS_ASSERT_EQUALS("fg", s3);
1652  s3 = xms::stRightCopy(s2, 7);
1653  TS_ASSERT_EQUALS("abcdefg", s2);
1654  TS_ASSERT_EQUALS("abcdefg", s3);
1655  s3 = xms::stRightCopy(s2, 8);
1656  TS_ASSERT_EQUALS("abcdefg", s2);
1657  TS_ASSERT_EQUALS("abcdefg", s3);
1658 
1659  // stEqualNoCase
1660 
1661  TS_ASSERT_EQUALS(true, xms::stEqualNoCase("ABC", "abc"));
1662  TS_ASSERT_EQUALS(true, xms::stEqualNoCase("abc", "ABC"));
1663  TS_ASSERT_EQUALS(false, xms::stEqualNoCase("ABC", "ABCD"));
1664  TS_ASSERT_EQUALS(false, xms::stEqualNoCase("abc", "abcd"));
1665  TS_ASSERT_EQUALS(false, xms::stEqualNoCase("BCD", "ABCD"));
1666  TS_ASSERT_EQUALS(false, xms::stEqualNoCase("bcd", "abcd"));
1667  TS_ASSERT_EQUALS(false, xms::stEqualNoCase("ABC", "DEFG"));
1668 
1669  // stRemove
1670 
1671  std::string s7 = "abcd abcd abcd";
1672  const std::string s8 = s7;
1673  std::string s9;
1674 
1675  xms::stRemove(s7, ' ');
1676  TS_ASSERT_EQUALS("abcdabcdabcd", s7);
1677  s7 = s8;
1678  xms::stRemove(s7, 'g');
1679  TS_ASSERT_EQUALS("abcd abcd abcd", s7);
1680  s7 = s8;
1681  xms::stRemove(s7, 'c');
1682  TS_ASSERT_EQUALS("abd abd abd", s7);
1683 
1684  // stRemoveCopy
1685  s9 = xms::stRemoveCopy(s8, ' ');
1686  TS_ASSERT_EQUALS("abcd abcd abcd", s8);
1687  TS_ASSERT_EQUALS("abcdabcdabcd", s9);
1688  s9 = xms::stRemoveCopy(s8, 'g');
1689  TS_ASSERT_EQUALS("abcd abcd abcd", s8);
1690  TS_ASSERT_EQUALS("abcd abcd abcd", s9);
1691  s9 = xms::stRemoveCopy(s8, 'c');
1692  TS_ASSERT_EQUALS("abcd abcd abcd", s8);
1693  TS_ASSERT_EQUALS("abd abd abd", s9);
1694 
1695 } // StringUtilUnitTests::testMisc
1696 //------------------------------------------------------------------------------
1698 //------------------------------------------------------------------------------
1700  double d1 = 123456.0123;
1701  double d2 = 0.123456789;
1702  int i = 123456789;
1703  std::stringstream ss;
1704  std::locale commaLocale(std::locale(), new xms::StCommaNumpunct());
1705  ss.imbue(commaLocale);
1706  ss << d1 << " " << d2 << " " << i;
1707  std::string s(ss.str());
1708  std::string expected = "123,456 0.123457 123,456,789";
1709  TS_ASSERT_EQUALS(expected, s);
1710 } // StringUtilUnitTests::testXmCommaNumpunct
1711 //------------------------------------------------------------------------------
1713 //------------------------------------------------------------------------------
1715  std::string s = "\t Testing \rextra \nspace \t \n\t";
1716  std::string expected = "Testing extra space";
1717  std::string modified = xms::stSimplified(s);
1718  TS_ASSERT_EQUALS(expected, modified);
1719 } // StringUtilUnitTests::testXmCommaNumpunct
1720 //------------------------------------------------------------------------------
1722 //------------------------------------------------------------------------------
1724  std::string container = "Isn't ThiS a Lovely day?";
1725  std::string str1 = "DAY";
1726  std::string str2 = "these a";
1727  bool expectedT = true;
1728  bool expectedF = false;
1729 
1730  bool test1 = xms::stContains(container, str1);
1731  TS_ASSERT_EQUALS(expectedT, test1);
1732 
1733  bool test2 = xms::stContains(container, str2);
1734  TS_ASSERT_EQUALS(expectedF, test2);
1735 
1736  bool test3 = xms::stContains(container, "THis");
1737  TS_ASSERT_EQUALS(expectedT, test3)
1738 } // StringUtilUnitTests::testSuIcontains()
1739 //------------------------------------------------------------------------------
1741 //------------------------------------------------------------------------------
1743  bool expectedT = true;
1744  bool expectedF = false;
1745  xms::VecStr container = {"me", "you", "they", "we", "Us"};
1746 
1747  bool test1 = xms::stVectorContainsString(container, "we");
1748  TS_ASSERT_EQUALS(expectedT, test1);
1749 
1750  bool test2 = xms::stVectorContainsString(container, "she");
1751  TS_ASSERT_EQUALS(expectedF, test2);
1752 } // StringUtilUnitTests::testSuVecContainsStr
1753 //------------------------------------------------------------------------------
1755 //------------------------------------------------------------------------------
1757  std::string out =
1758  xms::STRstd(0.0, 15, 15, xms::STR_FULLWIDTH | xms::STR_USEMAXPREC);
1759  std::string base = " 0.0";
1760  TS_ASSERT_EQUALS(base, out);
1761 } // StringUtilUnitTests::test_STRstd
1762 //------------------------------------------------------------------------------
1767 //------------------------------------------------------------------------------
1769  // TS_FAIL("NumTests::testPrec");
1770 
1771  // Test when we go into scientific notation with big and small numbers
1772  {
1773  // Create the "correct answer" vectors
1774  xms::VecDbl vec_values{0.0, 1e-30, 1e-15, 1e-6, 1e-5, 1e11, 1e12, 1e13};
1775  xms::VecInt vec_flags{0, 2, 2, 2, 0, 0, 2, 2};
1776  xms::VecInt vec_precs{1, 1, 1, 1, 5, 1, 1, 1};
1777 
1778  RunPrec(vec_values, vec_flags, vec_precs);
1779  }
1780 
1781 } // StringUtilUnitTests::testPrec
1782 //------------------------------------------------------------------------------
1787 //------------------------------------------------------------------------------
1789  // TS_FAIL("NumTests::testSTR");
1790 
1791  {
1792  xms::StTemp2DigitExponents use2DigitExponents;
1793  std::vector<ValStr> arr{
1794 
1795  // Test when we go into scientific notation with big and small numbers
1796  {0.0, -1, 15, 0, "0.0"},
1797  {1e-30, -1, 15, 0, "1.0e-30"},
1798  {1e-15, -1, 15, 0, "1.0e-15"},
1799  {1e-6, -1, 15, 0, "1.0e-06"},
1800  {1e-5, -1, 15, 0, "0.00001"},
1801  {1e11, -1, 15, 0, "100000000000.0"},
1802  {1e12, -1, 15, 0, "1.0e+12"},
1803  {1e13, -1, 15, 0, "1.0e+13"}
1804 
1805  // Test the STR_USEMAXPREC flag
1806  ,
1807  {0.0, -1, 15, xms::STR_USEMAXPREC, "0.0"},
1808  {1e-30, -1, 15, xms::STR_USEMAXPREC, "0.0"},
1809  {1e-15, -1, 15, xms::STR_USEMAXPREC, "0.0"},
1810  {1e-6, -1, 15, xms::STR_USEMAXPREC, "0.0"},
1811  {1e-5, -1, 15, xms::STR_USEMAXPREC, "0.0"},
1812  {1e11, -1, 15, xms::STR_USEMAXPREC, "100000000000.0"},
1813  {1e12, -1, 15, xms::STR_USEMAXPREC, "1.0e+12"},
1814  {1e13, -1, 15, xms::STR_USEMAXPREC, "1.0e+13"}
1815 
1816  // Test n
1817  ,
1818  {0.0, 3, 15, 0, "0.000"},
1819  {1e-30, 3, 15, 0, "0.000"},
1820  {1e-15, 3, 15, 0, "0.000"},
1821  {1e-6, 3, 15, 0, "0.000"},
1822  {1e-5, 3, 15, 0, "0.000"},
1823  {1e11, 3, 15, 0, "100000000000.000"},
1824  {1e12, 3, 15, 0, "1000000000000.000"},
1825  {1e13, 3, 15, 0, "10000000000000.000"}
1826 
1827  // Test n and STR_USEMAXPREC
1828  ,
1829  {0.0, 30, 15, xms::STR_USEMAXPREC, "0.0"},
1830  {1e-30, 30, 15, xms::STR_USEMAXPREC, "1.0e-30"},
1831  {1e-15, 30, 15, xms::STR_USEMAXPREC, "1.0e-15"},
1832  {1e-6, 30, 15, xms::STR_USEMAXPREC, "1.0e-06"},
1833  {1e-5, 30, 15, xms::STR_USEMAXPREC, "0.00001"},
1834  {1e11, 30, 15, xms::STR_USEMAXPREC, "100000000000.0"},
1835  {1e12, 30, 15, xms::STR_USEMAXPREC, "1.0e+12"},
1836  {1e13, 30, 15, xms::STR_USEMAXPREC, "1.0e+13"}
1837 
1838  // Test misc scenarios
1839  ,
1840  {-999999.0, -1, 8, xms::STR_FLOAT | xms::STR_SCIENTIFIC, "-1.0e+06"} // Bug 10580
1841 
1842  };
1843  xms::VecDbl vals;
1844  xms::VecStr strs;
1845  xms::VecInt ns, widths, flags;
1846  GetVectorsFromArray(arr, vals, ns, widths, flags, strs);
1847 
1848  RunSTR(vals, ns, widths, flags, strs);
1849  }
1850 
1851 } // StringUtilUnitTests::testSTR
1852 #endif
1853 //#endif
void testExtendedASCII()
Test stChangeExtendedAscii.
int m_oldOutputFormat
Saved output format to restore to orignal value.
Definition: StringUtil.h:51
std::vector< int > VecInt
short rename
Definition: vector.h:27
std::string stRemoveCopy(const std::string &str, char source)
Returns a copy of str with all instances of char source removed.
Definition: StringUtil.cpp:392
std::string & stTrimLeft(std::string &str, const std::string &delim)
Trims the leading delim characters from a string.
Definition: StringUtil.cpp:270
bool LT_EPS(_T A, _U B, _V epsilon)
Returns true if A < B equal within an epsilon (DBL EPS).
Definition: math.h:205
std::string & stLeft(std::string &a_source, size_t const a_length)
Modifies a_source to contain the first (leftmost) a_length characters.
Definition: StringUtil.cpp:466
std::string & stToUpper(std::string &str)
Modifies str to be all uppercase.
Definition: StringUtil.cpp:441
bool GT_EPS(_T A, _U B, _V epsilon)
Returns true if A > B equal within an epsilon (DBL EPS).
Definition: math.h:217
int stPrecision(double value, int &flags, int length)
Returns precision, or the number of digits to the right of the decimal needed to display the [value]...
Definition: StringUtil.cpp:673
void testSuIcontains()
Tests stContains.
_T Miabs(_T a)
Integer absolute value.
Definition: math.h:30
void testXmCommaNumpunct()
Tests StCommaNumpunct.
std::string STRstd(double a_value, int a_n, int width, int flags)
Get a properly formatted string from a double.
Definition: StringUtil.cpp:995
Use full width.
Definition: StringUtil.h:38
void test_STRstd()
Tests stVectorContainsString.
std::vector< double > VecDbl
short rename
Definition: vector.h:25
std::string & stTrim(std::string &str, const std::string &delim)
Trim the leading and trailing delim characters from a string.
Definition: StringUtil.cpp:306
bool stScientificNotation(const std::string &str, bool check_numeric)
Determines whether the given string is a number in scientific notation.
Definition: StringUtil.cpp:103
std::string stReplaceCopy(const std::string &str, char source, char dest)
Returns a copy of str with every instance of source replaced with dest.
Definition: StringUtil.cpp:318
void testNumAndSciNot()
Test stNumeric and stScientificNotation.
std::string stToLowerCopy(const std::string &str)
Returns a new string that is str with all characters lowercase.
Definition: StringUtil.cpp:412
bool stVectorContainsString(const VecStr &a_container, const std::string &str)
Checks if a vec of strings contains a string. Case sensitive.
Definition: StringUtil.cpp:527
std::vector< std::string > VecStr
short rename
Definition: vector.h:30
std::string stToUpperCopy(const std::string &str)
Returns a new string that is str with all characters uppercase.
Definition: StringUtil.cpp:432
std::string & stRight(std::string &a_source, size_t const a_length)
Modifies a_source to contain the last (rightmost) a_length characters.
Definition: StringUtil.cpp:537
bool stStringToDouble(const std::string &s, double &d)
Convert a string to an double.
Definition: StringUtil.cpp:646
StTemp2DigitExponents()
Temporarily output 2-digit exponents for floating point numbers to match C++ standard. Should be able to remove all instances of this class upon moving to Visual Studio 2015.
Definition: StringUtil.cpp:47
std::string stLeftCopy(const std::string &a_source, size_t const a_length)
Extracts first (leftmost) a_length characters from a_source returning a copy.
Definition: StringUtil.cpp:452
std::string stSimplified(const std::string &str)
Removes all white space from the passed string.
Definition: StringUtil.cpp:497
void testMakeUnique()
Test stMakeUnique.
Used to format numbers with comma separators.
Definition: StringUtil.h:137
void testSplit()
Test stSplit.
int stIndexOfElem(const VecStr &a_container, const std::string &str)
Iterates through a vec of strings and looks for the string. Case sensitive.
Definition: StringUtil.cpp:239
When constructed std::cout will temporarily output 2-digit exponents for floating point numbers...
Definition: StringUtil.h:44
bool stFindNoCase(const std::string &a, const std::string &b)
Returns true if a contains b while ignoring capitalization.
Definition: StringUtil.cpp:563
void testToUpper()
test stToUpper
virtual char do_thousands_sep() const
Returns the character used to separate numbers by thousands.
std::string & stReplace(std::string &str, char source, char dest)
Returns a reference to str, and replaces every instance of source replaced with dest.
Definition: StringUtil.cpp:345
int Round(_T a)
Rounds.
Definition: math.h:20
std::string stImplode(const std::vector< std::string > &source, const std::string &delim)
Joins the vector, inserting delim between each item.
Definition: StringUtil.cpp:216
void test_str2int()
test stStringToInt
Use maximum precision.
Definition: StringUtil.h:36
std::string & stToLower(std::string &str)
Modifies str to be all lowercase.
Definition: StringUtil.cpp:421
Float, not double.
Definition: StringUtil.h:32
std::string stTrimCopy(const std::string &str, const std::string &delim)
Trims the white space from a string. This involves creating a copy of the string (twice I believe)...
Definition: StringUtil.cpp:258
~StTemp2DigitExponents()
Revert back to 3-digit exponents for pre-Visual Studio 2015.
Definition: StringUtil.cpp:58
std::string stRightCopy(const std::string &a_source, size_t const a_length)
Extracts last (rightmost) a_length characters from a_source returning a copy.
Definition: StringUtil.cpp:484
void testPrec()
Test the Prec utility.
void testSuIndexOfElem()
Test stIndexOfElem()
std::string & stTrimRight(std::string &str, const std::string &delim)
Trims the trailing delim characters from a string.
Definition: StringUtil.cpp:288
void testCountChar()
Test stCountChar.
bool stMakeUnique(const std::set< std::string > &set_str, std::string &str)
Changes str to "str (2)" etc. if it is in set of set_str.
Definition: StringUtil.cpp:572
void testSuSimplified()
Tests stSimplified.
VecStr stExplode(const std::string &source, const std::string &a_delimiter)
Breaks the string into a vector of strings based on the delimiter.
Definition: StringUtil.cpp:144
bool stNumeric(const std::string &str)
Determines whether the given string is a valid number.
Definition: StringUtil.cpp:87
#define XM_ASSERT(x)
Does a regular ASSERT if xmAsserting, otherwise does nothing.
Definition: XmError.h:69
void testSuVecContainsStr()
Tests stVectorContainsString.
VecStr stSplit(const std::string &a_source, const std::string &a_delimiterList, bool a_delimiterCompressOn)
Breaks string into vector of strings based on one or more delimiters.
Definition: StringUtil.cpp:182
bool stEqualNoCase(const std::string &a, const std::string &b)
Returns true if a and b are equal while ignoring capitalization.
Definition: StringUtil.cpp:554
bool LT_TOL(_T A, _U B, _V tolerance)
Returns true if A < B equal within a tolerance.
Definition: math.h:277
bool stContains(const std::string &a_container, const std::string &a_substr)
Checks if first string contains second. Case insensitive.
Definition: StringUtil.cpp:509
Vector types for convenience.
void stChangeExtendedAscii(std::string &str, bool to_extended)
Replaces the Windows Latin-1 extended ASCII characters with standard ASCII and vice-versa.
Definition: StringUtil.cpp:117
std::string STRstd(T a_value, int a_n=0, int width=0, int flags=0)
Definition: StringUtil.h:127
Use scientific notation.
Definition: StringUtil.h:34
Functions and macros for assertion and checking for errors.
unsigned int stCountChar(const std::string &str, char c)
Counts the number of a given character in a string.
Definition: StringUtil.cpp:70
virtual std::string do_grouping() const
Returns the string defining how many numbers between separators.
void testSTR()
Test the STR utility.
#define TS_ASSERT_EQUALS_VEC(a, b)
Used to compare to vectors and give useful output information.
Definition: TestTools.h:171
std::string & stRemove(std::string &str, char source)
Removes all instances of char source from str and returns a reference to str.
Definition: StringUtil.cpp:403
void testMisc()
test various string utility functions.
bool stStringToInt(const std::string &s, int &i, int base)
Convert a string to an int.
Definition: StringUtil.cpp:625
void testImplodeExplode()
Test stImplode.
Use commas in string.
Definition: StringUtil.h:40
bool EQ_EPS(_T A, _U B, _V epsilon)
Returns true if A == B within an epsilon (DBL EPS).
Definition: math.h:193
void testReplace()
Test stReplace.
void testTrim()
Test stTrim.