NumericString.h 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  1. //
  2. // NumericString.h
  3. //
  4. // $Id: //poco/1.4/Foundation/include/Poco/NumericString.h#1 $
  5. //
  6. // Library: Foundation
  7. // Package: Core
  8. // Module: NumericString
  9. //
  10. // Numeric string utility functions.
  11. //
  12. // Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.
  13. // and Contributors.
  14. //
  15. // Permission is hereby granted, free of charge, to any person or organization
  16. // obtaining a copy of the software and accompanying documentation covered by
  17. // this license (the "Software") to use, reproduce, display, distribute,
  18. // execute, and transmit the Software, and to prepare derivative works of the
  19. // Software, and to permit third-parties to whom the Software is furnished to
  20. // do so, all subject to the following:
  21. //
  22. // The copyright notices in the Software and this entire statement, including
  23. // the above license grant, this restriction and the following disclaimer,
  24. // must be included in all copies of the Software, in whole or in part, and
  25. // all derivative works of the Software, unless such copies or derivative
  26. // works are solely in the form of machine-executable object code generated by
  27. // a source language processor.
  28. //
  29. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  30. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  31. // FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
  32. // SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
  33. // FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
  34. // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  35. // DEALINGS IN THE SOFTWARE.
  36. //
  37. #ifndef Foundation_NumericString_INCLUDED
  38. #define Foundation_NumericString_INCLUDED
  39. #include "Poco/Foundation.h"
  40. #include "Poco/FPEnvironment.h"
  41. #ifdef min
  42. #undef min
  43. #endif
  44. #ifdef max
  45. #undef max
  46. #endif
  47. #include <limits>
  48. #include <cmath>
  49. #if !defined(POCO_NO_LOCALE)
  50. #include <locale>
  51. #endif
  52. namespace Poco {
  53. inline char decimalSeparator()
  54. /// Returns decimal separator from global locale or
  55. /// default '.' for platforms where locale is unavailable.
  56. {
  57. #if !defined(POCO_NO_LOCALE)
  58. return std::use_facet<std::numpunct<char> >(std::locale()).decimal_point();
  59. #else
  60. return '.';
  61. #endif
  62. }
  63. inline char thousandSeparator()
  64. /// Returns thousand separator from global locale or
  65. /// default ',' for platforms where locale is unavailable.
  66. {
  67. #if !defined(POCO_NO_LOCALE)
  68. return std::use_facet<std::numpunct<char> >(std::locale()).thousands_sep();
  69. #else
  70. return ',';
  71. #endif
  72. }
  73. template <typename I>
  74. bool strToInt(const char* pStr, I& result, short base, char thSep = ',')
  75. /// Converts zero-terminated character array to integer number;
  76. /// Thousand separators are recognized for base10 and current locale;
  77. /// it is silently skipped but not verified for correct positioning.
  78. /// Function returns true if succesful. If parsing was unsuccesful,
  79. /// the return value is false with the result value undetermined.
  80. {
  81. if (!pStr) return false;
  82. while (isspace(*pStr)) ++pStr;
  83. if (*pStr == '\0') return false;
  84. char sign = 1;
  85. if ((base == 10) && (*pStr == '-'))
  86. {
  87. sign = -1;
  88. ++pStr;
  89. }
  90. else if (*pStr == '+') ++pStr;
  91. // parser states:
  92. const char STATE_SIGNIFICANT_DIGITS = 1;
  93. char state = 0;
  94. result = 0;
  95. I limitCheck = std::numeric_limits<I>::max() / base;
  96. for (; *pStr != '\0'; ++pStr)
  97. {
  98. switch (*pStr)
  99. {
  100. case 'x': case 'X':
  101. if (base != 0x10) return false;
  102. case '0':
  103. if (state < STATE_SIGNIFICANT_DIGITS) break;
  104. case '1': case '2': case '3': case '4':
  105. case '5': case '6': case '7':
  106. if (state < STATE_SIGNIFICANT_DIGITS) state = STATE_SIGNIFICANT_DIGITS;
  107. if (result > limitCheck) return false;
  108. result = result * base + (*pStr - '0');
  109. break;
  110. case '8': case '9':
  111. if ((base == 10) || (base == 0x10))
  112. {
  113. if (state < STATE_SIGNIFICANT_DIGITS) state = STATE_SIGNIFICANT_DIGITS;
  114. if (result > limitCheck) return false;
  115. result = result * base + (*pStr - '0');
  116. }
  117. else return false;
  118. break;
  119. case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
  120. if (base != 0x10) return false;
  121. if (state < STATE_SIGNIFICANT_DIGITS) state = STATE_SIGNIFICANT_DIGITS;
  122. if (result > limitCheck) return false;
  123. result = result * base + (10 + *pStr - 'a');
  124. break;
  125. case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
  126. if (base != 0x10) return false;
  127. if (state < STATE_SIGNIFICANT_DIGITS) state = STATE_SIGNIFICANT_DIGITS;
  128. if (result > limitCheck) return false;
  129. result = result * base + (10 + *pStr - 'A');
  130. break;
  131. case 'U':
  132. case 'u':
  133. case 'L':
  134. case 'l':
  135. goto done;
  136. case '.':
  137. if ((base == 10) && (thSep == '.')) break;
  138. else return false;
  139. case ',':
  140. if ((base == 10) && (thSep == ',')) break;
  141. else return false;
  142. case ' ':
  143. if ((base == 10) && (thSep == ' ')) break;
  144. case '\t':
  145. case '\n':
  146. case '\v':
  147. case '\f':
  148. case '\r':
  149. goto done;
  150. default:
  151. return false;
  152. }
  153. }
  154. done:
  155. if ((sign < 0) && (base == 10)) result *= sign;
  156. return true;
  157. }
  158. template <typename I>
  159. bool strToInt(const std::string& str, I& result, short base, char thSep = ',')
  160. /// Converts string to integer number;
  161. /// This is a wrapper function, for details see see the
  162. /// bool strToInt(const char*, I&, short, char) implementation.
  163. {
  164. return strToInt(str.c_str(), result, base, thSep);
  165. }
  166. namespace Impl {
  167. static char DUMMY_EXP_UNDERFLOW = 0; // dummy default val
  168. }
  169. template <typename F>
  170. bool strToFloat (const char* pStr, F& result, char& eu = Impl::DUMMY_EXP_UNDERFLOW, char decSep = '.', char thSep = ',')
  171. /// Converts zero-terminated array to floating-point number;
  172. /// Returns true if succesful. Exponent underflow (i.e. loss of precision)
  173. /// is signalled in eu. Thousand separators are recognized for the locale
  174. /// and silently skipped but not verified for correct positioning.
  175. ///
  176. /// If parsing was unsuccesful, the return value is false with
  177. /// result and eu values undetermined.
  178. {
  179. poco_assert (decSep != thSep);
  180. if (pStr == 0 || *pStr == '\0') return false;
  181. // parser states:
  182. const char STATE_LEADING_SPACES = 0;
  183. const char STATE_DIGITS_BEFORE_DEC_POINT = 1;
  184. const char STATE_DIGITS_AFTER_DEC_POINT = 2;
  185. const char STATE_EXP_CHAR = 3;
  186. const char STATE_EXP_DIGITS = 4;
  187. const char STATE_SUFFIX = 5; // 'f' suffix
  188. char numSign = 1, expSign = 1;
  189. char state = STATE_LEADING_SPACES;
  190. F mantissa = 0.0, exponent = 0.0;
  191. F pow10 = 1.;
  192. result = 0.0;
  193. eu = 0;
  194. for (; *pStr != '\0'; ++pStr)
  195. {
  196. switch (*pStr)
  197. {
  198. case '.':
  199. if (decSep == '.')
  200. {
  201. if (state >= STATE_DIGITS_AFTER_DEC_POINT) return false;
  202. state = STATE_DIGITS_AFTER_DEC_POINT;
  203. break;
  204. }
  205. else if ((thSep == '.') && (state == STATE_DIGITS_BEFORE_DEC_POINT))
  206. break;
  207. else
  208. return false;
  209. case ',':
  210. if (decSep == ',')
  211. {
  212. if (state >= STATE_DIGITS_AFTER_DEC_POINT) return false;
  213. state = STATE_DIGITS_AFTER_DEC_POINT;
  214. break;
  215. }
  216. else if ((thSep == ',') && (state == STATE_DIGITS_BEFORE_DEC_POINT))
  217. break;
  218. else
  219. return false;
  220. case ' ': // space (SPC)
  221. if ((thSep == ' ') && (state == STATE_DIGITS_BEFORE_DEC_POINT)) break;
  222. case '\t': // horizontal tab (TAB)
  223. case '\n': // line feed (LF)
  224. case '\v': // vertical tab (VT)
  225. case '\f': // form feed (FF)
  226. case '\r': // carriage return (CR)
  227. if ((state >= STATE_DIGITS_AFTER_DEC_POINT) || (state >= STATE_EXP_DIGITS))
  228. break;
  229. else if ((state > STATE_LEADING_SPACES) && (state < STATE_DIGITS_AFTER_DEC_POINT))
  230. return false;
  231. break;
  232. case '-':
  233. if (state == STATE_LEADING_SPACES)
  234. numSign = -1;
  235. else if (state == STATE_EXP_CHAR) // exponential char
  236. expSign = -1;
  237. else return false;
  238. case '+':
  239. break;
  240. case '0':
  241. case '1':
  242. case '2':
  243. case '3':
  244. case '4':
  245. case '5':
  246. case '6':
  247. case '7':
  248. case '8':
  249. case '9':
  250. if (state >= STATE_SUFFIX) return false; // constant suffix
  251. if (state <= STATE_DIGITS_BEFORE_DEC_POINT) // integral part digits
  252. {
  253. result = result * 10 + (*pStr - '0');
  254. state = STATE_DIGITS_BEFORE_DEC_POINT;
  255. }
  256. else if (state <= STATE_DIGITS_AFTER_DEC_POINT) // fractional part digits
  257. {
  258. mantissa += (*pStr - '0') / (pow10 *= 10.);
  259. state = STATE_DIGITS_AFTER_DEC_POINT;
  260. }
  261. else if (state <= STATE_EXP_DIGITS) // exponent digits
  262. {
  263. exponent = exponent * 10 + (*pStr - '0');
  264. state = STATE_EXP_DIGITS;
  265. }
  266. else return false;
  267. break;
  268. case 'E':
  269. case 'e':
  270. if (state > STATE_DIGITS_AFTER_DEC_POINT) return false;
  271. state = STATE_EXP_CHAR;
  272. break;
  273. case 'F':
  274. case 'f':
  275. state = STATE_SUFFIX;
  276. break;
  277. default:
  278. return false;
  279. }
  280. }
  281. if (exponent > std::numeric_limits<F>::max_exponent10)
  282. {
  283. eu = expSign;
  284. exponent = std::numeric_limits<F>::max_exponent10;
  285. }
  286. result += mantissa;
  287. if (numSign != 1) result *= numSign;
  288. if (exponent > 1.0)
  289. {
  290. F scale = std::pow(10., exponent);
  291. result = (expSign < 0) ? (result / scale) : (result * scale);
  292. }
  293. return (state != STATE_LEADING_SPACES) && // empty/zero-length string
  294. !FPEnvironment::isInfinite(result) &&
  295. !FPEnvironment::isNaN(result);
  296. }
  297. template <typename F>
  298. bool strToFloat (const std::string& s, F& result, char& eu = Impl::DUMMY_EXP_UNDERFLOW, char decSep = '.', char thSep = ',')
  299. /// Converts string to floating-point number;
  300. /// This is a wrapper function, for details see see the
  301. /// bool strToFloat(const char*, F&, char&, char, char) implementation.
  302. {
  303. return strToFloat(s.c_str(), result, eu, decSep, thSep);
  304. }
  305. } // namespace Poco
  306. #endif // Foundation_NumericString_INCLUDED