xtd 0.2.0
__parse.hpp
Go to the documentation of this file.
1
3#pragma once
5#if !defined(__XTD_CORE_INTERNAL__)
6#error "Do not include this file: Internal use only"
7#endif
9
10#include "../helpers/throw_helper.hpp"
11#include "../number_styles.hpp"
12#include "../types.hpp"
13#include <locale>
14#include <limits>
15#include <string>
16#include <sstream>
17
19template<class char_t>
20inline std::basic_string<char_t> __parse_remove_decorations(const std::basic_string<char_t>& s, xtd::number_styles styles) {
21 std::basic_string<char_t> str(s);
23 while (str.size() > 0 && (str[0] == 9 || str[0] == 10 || str[0] == 11 || str[0] == 12 || str[0] == 13 || str[0] == 32))
24 str.erase(0, 1);
25 }
27 while (str.size() > 0 && (str[str.size() - 1] == 9 || str[str.size() - 1] == 10 || str[str.size() - 1] == 11 || str[str.size() - 1] == 12 || str[str.size() - 1] == 13 || str[str.size() - 1] == 32))
28 str.erase(str.size() - 1, 1);
29 }
30 if ((styles & xtd::number_styles::allow_currency_symbol) == xtd::number_styles::allow_currency_symbol && str.find(std::use_facet<std::moneypunct<char_t>>(std::locale()).curr_symbol()) == 0) str.erase(0, std::use_facet<std::moneypunct<char_t>>(std::locale()).curr_symbol().size());
31 if ((styles & xtd::number_styles::allow_currency_symbol) == xtd::number_styles::allow_currency_symbol && str.rfind(std::use_facet<std::moneypunct<char_t>>(std::locale()).curr_symbol()) + std::use_facet<std::moneypunct<char_t>>(std::locale()).curr_symbol().size() == str.size()) str.resize(str.size() - std::use_facet<std::moneypunct<char_t>>(std::locale()).curr_symbol().size());
32 if ((styles & xtd::number_styles::allow_binary_specifier) == xtd::number_styles::allow_binary_specifier && (str.find("0b") == 0 || str.find("0B") == 0)) str.erase(0, 2);
33 if ((styles & xtd::number_styles::allow_octal_specifier) == xtd::number_styles::allow_octal_specifier && str.find('0') == 0) str.erase(0, 1);
34 if ((styles & xtd::number_styles::allow_hex_specifier) == xtd::number_styles::allow_hex_specifier && (str.find("0x") == 0 || str.find("0X") == 0)) str.erase(0, 2);
35 return str;
36}
37
38template<class char_t>
39inline int __parse_remove_signs(std::basic_string<char_t>& str, xtd::number_styles styles) {
40 int sign = 0;
41
42 while ((styles & xtd::number_styles::allow_leading_sign) == xtd::number_styles::allow_leading_sign && str.find('+') == 0) {
43 if (sign != 0) xtd::helpers::throw_helper::throws(xtd::helpers::exception_case::format, "String contains more than one sign");
44 str = str.substr(1, str.size() - 1);
45 sign += 1;
46 }
47
48 while ((styles & xtd::number_styles::allow_leading_sign) == xtd::number_styles::allow_leading_sign && str.find('-') == 0) {
49 if (sign != 0) xtd::helpers::throw_helper::throws(xtd::helpers::exception_case::format, "String contains more than one sign");
50 str = str.substr(1, str.size() - 1);
51 sign -= 1;
52 }
53
54 while ((styles & xtd::number_styles::allow_trailing_sign) == xtd::number_styles::allow_trailing_sign && str.rfind('+') + 1 == str.size()) {
55 if (sign != 0) xtd::helpers::throw_helper::throws(xtd::helpers::exception_case::format, "String contains more than one sign");
56 str.pop_back();
57 sign += 1;
58 }
59
60 while ((styles & xtd::number_styles::allow_trailing_sign) == xtd::number_styles::allow_trailing_sign && str.rfind('-') + 1 == str.size()) {
61 if (sign != 0) xtd::helpers::throw_helper::throws(xtd::helpers::exception_case::format, "String contains more than one sign");
62 str.pop_back();
63 sign -= 1;
64 }
65
66 while ((styles & xtd::number_styles::allow_parentheses) == xtd::number_styles::allow_parentheses && str.find('(') == 0 && str.rfind(')') + 1 == str.size()) {
67 str = str.substr(1, str.size() - 2);
68 if (sign != 0) xtd::helpers::throw_helper::throws(xtd::helpers::exception_case::format, "String contains more than one sign");
69 sign -= 1;
70 }
71 return sign;
72}
73
74template<class char_t>
75inline void __parse_check_valid_characters(const std::basic_string<char_t>& str, xtd::number_styles styles) {
76 std::basic_string<char_t> valid_characters = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
79 if ((styles & xtd::number_styles::allow_hex_specifier) == xtd::number_styles::allow_hex_specifier) valid_characters += std::basic_string<char_t> {'A', 'B', 'C', 'D', 'E', 'F', 'a', 'b', 'c', 'd', 'e', 'f'};
80 if ((styles & xtd::number_styles::allow_decimal_point) == xtd::number_styles::allow_decimal_point) valid_characters += std::basic_string<char_t> {std::use_facet<std::numpunct<char_t>>(std::locale()).decimal_point(), '.'};
81 if ((styles & xtd::number_styles::allow_thousands) == xtd::number_styles::allow_thousands) valid_characters += std::use_facet<std::numpunct<char_t>>(std::locale()).thousands_sep();
82 if ((styles & xtd::number_styles::allow_exponent) == xtd::number_styles::allow_exponent) valid_characters += std::basic_string<char_t> {'E', 'e', '+', '-'};
83
84 for (auto c : str) {
85 if (valid_characters.find(c) == std::basic_string<char_t>::npos)
87 }
88
90 size_t index = str.find(std::use_facet<std::numpunct<char_t>>(std::locale()).decimal_point());
91 if (index != std::basic_string<char_t>::npos && str.find(std::use_facet<std::numpunct<char_t>>(std::locale()).decimal_point(), index + 1) != std::basic_string<char_t>::npos)
93 }
94
96 size_t index = 1;
97 while ((index = str.find(std::use_facet<std::numpunct<char_t>>(std::locale()).thousands_sep(), index)) != std::basic_string<char_t>::npos) {
98 if (str[index - 1] == std::use_facet<std::numpunct<char_t>>(std::locale()).thousands_sep())
100 ++index;
101 }
102 }
103
105 size_t index = str.find('+');
106 if (index == std::basic_string<char_t>::npos) index = str.find('-');
107 if (index != std::basic_string<char_t>::npos && str[index - 1] != 'e' && str[index - 1] != 'E')
109 }
110}
111
112template<class value_t, class char_t>
113inline value_t __parse_floating_point(const std::basic_string<char_t>& str, int sign, xtd::number_styles styles) {
114 long double result;
116 result = std::stold(str, nullptr);
117 else {
118 std::stringstream ss(str);
119 ss.imbue(std::locale());
120 ss >> result;
121 }
122
123 result = sign < 0 ? -result : result;
124 if (result < std::numeric_limits<value_t>::lowest() || result > std::numeric_limits<value_t>::max()) xtd::helpers::throw_helper::throws(xtd::helpers::exception_case::overflow);
125 return static_cast<value_t>(result);
126}
127
128template<class value_t, class char_t>
129inline value_t __parse_signed(const std::basic_string<char_t>& str, int base, int sign, xtd::number_styles styles) {
130 long long result;
132 result = std::stoll(str, nullptr, base);
133 else {
134 std::stringstream ss(str);
135 ss.imbue(std::locale());
136 ss >> result;
137 }
138
139 result = sign < 0 ? -result : result;
140 if (result < std::numeric_limits<value_t>::lowest() || result > std::numeric_limits<value_t>::max()) xtd::helpers::throw_helper::throws(xtd::helpers::exception_case::overflow);
141 return static_cast<value_t>(result);
142}
143
144template<class value_t, class char_t>
145inline value_t __parse_unsigned(const std::basic_string<char_t>& str, int base, xtd::number_styles styles) {
146 unsigned long long result = 0;
148 result = std::stoull(str, nullptr, base);
149 else {
150 std::stringstream ss(str);
151 ss.imbue(std::locale());
152 ss >> result;
153 }
154
155 if (result > std::numeric_limits<value_t>::max()) xtd::helpers::throw_helper::throws(xtd::helpers::exception_case::overflow);
156 return static_cast<value_t>(result);
157}
158
159template<class value_t, class char_t>
160inline value_t __parse_floating_point_number(const std::basic_string<char_t>& s, xtd::number_styles styles, const std::locale& locale) {
161 if ((styles & xtd::number_styles::binary_number) == xtd::number_styles::binary_number) xtd::helpers::throw_helper::throws(xtd::helpers::exception_case::format, "xtd::number_styles::binary_number not supported by floating point");
162 if ((styles & xtd::number_styles::octal_number) == xtd::number_styles::octal_number) xtd::helpers::throw_helper::throws(xtd::helpers::exception_case::format, "xtd::number_styles::octal_number not supported by floating point");
163 if ((styles & xtd::number_styles::hex_number) == xtd::number_styles::hex_number) xtd::helpers::throw_helper::throws(xtd::helpers::exception_case::format, "xtd::number_styles::hex_number not supported by floating point");
164
165 auto lower_str = s;
166 for (auto& c : lower_str)
167 c = static_cast<char>(std::tolower(c));
168 if (s == "inf") return std::numeric_limits<value_t>::infinity();
169 if (s == "-inf") return -std::numeric_limits<value_t>::infinity();
170 if (s == "nan") return std::numeric_limits<value_t>::quiet_NaN();
171
172 std::basic_string<char_t> str = __parse_remove_decorations(s, styles);
173 int sign = __parse_remove_signs(str, styles);
174
175 __parse_check_valid_characters(str, styles);
176
177 long double result;
179 result = std::stold(str, nullptr);
180 else {
181 std::stringstream ss(str);
182 ss.imbue(locale);
183 ss >> result;
184 }
185
186 result = sign < 0 ? -result : result;
187 if (result < std::numeric_limits<value_t>::lowest() || result > std::numeric_limits<value_t>::max()) xtd::helpers::throw_helper::throws(xtd::helpers::exception_case::overflow);
188 return static_cast<value_t>(result);
189}
190
191template<class value_t, class char_t>
192inline value_t __parse_number(const std::basic_string<char_t>& s, xtd::number_styles styles) {
196
197 int base = 10;
201
202 std::basic_string<char_t> str = __parse_remove_decorations(s, styles);
203 int sign = __parse_remove_signs(str, styles);
204
205 __parse_check_valid_characters(str, styles);
206
207 if (std::is_floating_point<value_t>::value || (styles & xtd::number_styles::allow_exponent) == xtd::number_styles::allow_exponent) return __parse_floating_point<value_t>(str, sign, styles);
208 return __parse_signed<value_t>(str, base, sign, styles);
209}
210
211template<class value_t, class char_t>
212inline value_t __parse_unsigned_number(const std::basic_string<char_t>& s, xtd::number_styles styles) {
216
217 int base = 10;
221
222 std::basic_string<char_t> str = __parse_remove_decorations(s, styles);
223 if (__parse_remove_signs(str, styles) < 0) xtd::helpers::throw_helper::throws(xtd::helpers::exception_case::format, "unsigned type can't have minus sign");
224
225 __parse_check_valid_characters(str, styles);
226
227 if ((styles & xtd::number_styles::allow_exponent) == xtd::number_styles::allow_exponent) return __parse_floating_point<value_t>(str, 0, styles);
228 return __parse_unsigned<value_t>(str, base, styles);
229}
230
231template<class value_t>
232value_t __parse_enum(const std::string& str);
static void throws(xtd::helpers::exception_case exception_case, const source_location &location=source_location::current())
Throws an exption with specified exception case.
@ overflow
Arithmetic overflow.
@ format
The format is not valid.
size_t size
Represents a size of any object in bytes.
Definition size.hpp:23
number_styles
Determines the styles permitted in numeric string arguments that are passed to the xtd::parse and xtd...
Definition number_styles.hpp:16
@ allow_thousands
Indicates that the numeric string can have group separators, such as symbols that separate hundreds f...
@ allow_decimal_point
Indicates that the numeric string can have a decimal point. If the number_styles value includes the a...
@ allow_trailing_sign
Indicates that the numeric string can have a trailing sign. Valid trailing sign characters are determ...
@ allow_leading_sign
Indicates that the numeric string can have a leading sign.
@ none
Indicates that no style elements, such as leading or trailing white space, thousands separators,...
@ allow_parentheses
Indicates that the numeric string can have one pair of parentheses enclosing the number....
@ binary_number
Indicates that the allow_leading_white, allow_trailing_white, and allow_binary_specifier styles are u...
@ allow_exponent
Indicates that the numeric string can be in exponential notation. The allow_exponent flag allows the ...
@ allow_hex_specifier
Indicates that the numeric string represents a hexadecimal value. Valid hexadecimal values include th...
@ allow_octal_specifier
Indicates that the numeric string represents a octal value. Valid octal values include the numeric di...
@ allow_leading_white
Indicates that leading white-space characters can be present in the parsed string....
@ octal_number
Indicates that the allow_leading_white, allow_trailing_white, and allow_octal_specifier styles are us...
@ allow_trailing_white
Indicates that trailing white-space characters can be present in the parsed string....
@ allow_currency_symbol
Indicates that the numeric string can contain a currency symbol. Valid currency symbols are determine...
@ hex_number
Indicates that the allow_leading_white, allow_trailing_white, and allow_hex_specifier styles are used...
@ allow_binary_specifier
Indicates that the numeric string represents a binary value. Valid binary values include the numeric ...
@ s
The S key.
@ c
The C key.