Mercurial > hg > octave-jordi
comparison src/DLD-FUNCTIONS/str2double.cc @ 14077:b6eeeb67fa3f stable
str2double: return NaN for things like "1 2 3 4" (bug #34713).
* str2double.cc (single_num, extract_num): Skip spaces as needed.
(str2double1): Don't skip all spaces.
author | John W. Eaton <jwe@octave.org> |
---|---|
date | Tue, 20 Dec 2011 18:06:07 -0500 |
parents | e81ddf9cacd5 |
children | c3ea07298af4 |
comparison
equal
deleted
inserted
replaced
14076:9aff66860e03 | 14077:b6eeeb67fa3f |
---|---|
44 | 44 |
45 static std::istringstream& | 45 static std::istringstream& |
46 single_num (std::istringstream& is, double& num) | 46 single_num (std::istringstream& is, double& num) |
47 { | 47 { |
48 char c = is.peek (); | 48 char c = is.peek (); |
49 | |
50 // Skip spaces. | |
51 while (isspace (c)) | |
52 { | |
53 is.get (); | |
54 c = is.peek (); | |
55 } | |
56 | |
49 if (c == 'I') | 57 if (c == 'I') |
50 { | 58 { |
51 // It's infinity. | 59 // It's infinity. |
52 is.get (); | 60 is.get (); |
53 char c1 = is.get (), c2 = is.get (); | 61 char c1 = is.get (), c2 = is.get (); |
91 extract_num (std::istringstream& is, double& num, bool& imag, bool& have_sign) | 99 extract_num (std::istringstream& is, double& num, bool& imag, bool& have_sign) |
92 { | 100 { |
93 have_sign = imag = false; | 101 have_sign = imag = false; |
94 | 102 |
95 char c = is.peek (); | 103 char c = is.peek (); |
104 | |
105 // Skip leading spaces. | |
106 while (isspace (c)) | |
107 { | |
108 is.get (); | |
109 c = is.peek (); | |
110 } | |
111 | |
96 bool negative = false; | 112 bool negative = false; |
97 | 113 |
98 // Accept leading sign. | 114 // Accept leading sign. |
99 if (c == '+' || c == '-') | 115 if (c == '+' || c == '-') |
100 { | 116 { |
101 negative = c == '-'; | 117 negative = c == '-'; |
102 is.get (); | 118 is.get (); |
103 c = is.peek (); | 119 c = is.peek (); |
104 have_sign = true; | 120 have_sign = true; |
121 } | |
122 | |
123 // Skip spaces after sign. | |
124 while (isspace (c)) | |
125 { | |
126 is.get (); | |
127 c = is.peek (); | |
105 } | 128 } |
106 | 129 |
107 // It's i*num or just i. | 130 // It's i*num or just i. |
108 if (is_imag_unit (c)) | 131 if (is_imag_unit (c)) |
109 { | 132 { |
110 c = is.get (); | 133 c = is.get (); |
111 imag = true; | 134 imag = true; |
112 char cn = is.peek (); | 135 char cn = is.peek (); |
136 | |
137 // Skip spaces after imaginary unit. | |
138 while (isspace (cn)) | |
139 { | |
140 is.get (); | |
141 cn = is.peek (); | |
142 } | |
143 | |
113 if (cn == '*') | 144 if (cn == '*') |
114 { | 145 { |
115 // Multiplier follows, we extract it as a number. | 146 // Multiplier follows, we extract it as a number. |
116 is.get (); | 147 is.get (); |
117 single_num (is, num); | 148 single_num (is, num); |
124 // It's num, num*i, or numi. | 155 // It's num, num*i, or numi. |
125 single_num (is, num); | 156 single_num (is, num); |
126 if (is.good ()) | 157 if (is.good ()) |
127 { | 158 { |
128 c = is.peek (); | 159 c = is.peek (); |
160 | |
161 // Skip spaces after number. | |
162 while (isspace (c)) | |
163 { | |
164 is.get (); | |
165 c = is.peek (); | |
166 } | |
167 | |
129 if (c == '*') | 168 if (c == '*') |
130 { | 169 { |
131 is.get (); | 170 is.get (); |
132 c = is.get (); | 171 c = is.peek (); |
172 | |
173 // Skip spaces after operator. | |
174 while (isspace (c)) | |
175 { | |
176 is.get (); | |
177 c = is.peek (); | |
178 } | |
179 | |
133 if (is_imag_unit (c)) | 180 if (is_imag_unit (c)) |
134 { | 181 { |
135 imag = true; | 182 imag = true; |
136 is.peek (); | 183 is.get (); |
184 is.peek (); // Sets eof bit. | |
137 } | 185 } |
138 else | 186 else |
139 is.setstate (std::ios::failbit); // indicate that read has failed. | 187 is.setstate (std::ios::failbit); // indicate that read has failed. |
140 } | 188 } |
141 else if (is_imag_unit (c)) | 189 else if (is_imag_unit (c)) |
142 { | 190 { |
143 imag = true; | 191 imag = true; |
144 is.get (); | 192 is.get (); |
145 is.peek (); | 193 is.peek (); // Sets eof bit. |
146 } | 194 } |
147 } | 195 } |
148 } | 196 } |
149 | 197 |
150 if (negative) | 198 if (negative) |
179 { | 227 { |
180 Complex val (0.0, 0.0); | 228 Complex val (0.0, 0.0); |
181 | 229 |
182 std::string str = str_arg; | 230 std::string str = str_arg; |
183 | 231 |
232 // FIXME -- removing all commas does too much... | |
184 std::string::iterator se = str.end (); | 233 std::string::iterator se = str.end (); |
185 | |
186 // Remove commas (thousand separators) and spaces. | |
187 se = std::remove (str.begin (), se, ','); | 234 se = std::remove (str.begin (), se, ','); |
188 se = std::remove (str.begin (), se, ' '); | |
189 str.erase (se, str.end ()); | 235 str.erase (se, str.end ()); |
190 | |
191 std::istringstream is (str); | 236 std::istringstream is (str); |
237 | |
192 double num; | 238 double num; |
193 bool i1, i2, s1, s2; | 239 bool i1, i2, s1, s2; |
194 | 240 |
195 if (is.eof ()) | 241 if (is.eof ()) |
196 val = octave_NaN; | 242 val = octave_NaN; |
303 %!assert (str2double (".5*i + 3.5"), 3.5+0.5i) | 349 %!assert (str2double (".5*i + 3.5"), 3.5+0.5i) |
304 %!assert (str2double ("1e-3 + i*.25"), 1e-3 + 0.25i) | 350 %!assert (str2double ("1e-3 + i*.25"), 1e-3 + 0.25i) |
305 %!assert (str2double (["2 + j";"1.25e-3";"-05"]), [2+i; 1.25e-3; -5]) | 351 %!assert (str2double (["2 + j";"1.25e-3";"-05"]), [2+i; 1.25e-3; -5]) |
306 %!assert (str2double ({"2 + j","1.25e-3","-05"}), [2+i, 1.25e-3, -5]) | 352 %!assert (str2double ({"2 + j","1.25e-3","-05"}), [2+i, 1.25e-3, -5]) |
307 %!assert (str2double (1), NaN) | 353 %!assert (str2double (1), NaN) |
354 %!assert (str2double ("1 2 3 4"), NaN) | |
308 %!assert (str2double ("Hello World"), NaN) | 355 %!assert (str2double ("Hello World"), NaN) |
309 %!assert (str2double ("NaN"), NaN) | 356 %!assert (str2double ("NaN"), NaN) |
310 %!assert (str2double ("NA"), NA) | 357 %!assert (str2double ("NA"), NA) |
311 %!assert (str2double ("Inf"), Inf) | 358 %!assert (str2double ("Inf"), Inf) |
312 %!assert (str2double ("-Inf"), -Inf) | 359 %!assert (str2double ("-Inf"), -Inf) |