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)