GNU Octave  3.8.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
str2double.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 2010-2013 Jaroslav Hajek
4 Copyright (C) 2010 VZLU Prague
5 
6 This file is part of Octave.
7 
8 Octave is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by the
10 Free Software Foundation; either version 3 of the License, or (at your
11 option) any later version.
12 
13 Octave is distributed in the hope that it will be useful, but WITHOUT
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 for more details.
17 
18 You should have received a copy of the GNU General Public License
19 along with Octave; see the file COPYING. If not, see
20 <http://www.gnu.org/licenses/>.
21 
22 */
23 
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27 
28 #include <string>
29 #include <cctype>
30 #include <sstream>
31 #include <algorithm>
32 
33 #include "lo-ieee.h"
34 
35 #include "Cell.h"
36 #include "ov.h"
37 #include "defun.h"
38 #include "gripes.h"
39 #include "utils.h"
40 
41 static inline bool
42 is_imag_unit (int c)
43 { return c == 'i' || c == 'j'; }
44 
45 static double
46 single_num (std::istringstream& is)
47 {
48  double num;
49 
50  char c = is.peek ();
51 
52  // Skip spaces.
53  while (isspace (c))
54  {
55  is.get ();
56  c = is.peek ();
57  }
58 
59  if (std::toupper (c) == 'I')
60  {
61  // It's infinity.
62  is.get ();
63  char c1 = is.get (), c2 = is.get ();
64  if (std::tolower (c1) == 'n' && std::tolower (c2) == 'f')
65  {
66  num = octave_Inf;
67  is.peek (); // May set EOF bit.
68  }
69  else
70  is.setstate (std::ios::failbit); // indicate that read has failed.
71  }
72  else if (c == 'N')
73  {
74  // It's NA or NaN
75  is.get ();
76  char c1 = is.get ();
77  if (c1 == 'A')
78  {
79  num = octave_NA;
80  is.peek (); // May set EOF bit.
81  }
82  else
83  {
84  char c2 = is.get ();
85  if (c1 == 'a' && c2 == 'N')
86  {
87  num = octave_NaN;
88  is.peek (); // May set EOF bit.
89  }
90  else
91  is.setstate (std::ios::failbit); // indicate that read has failed.
92  }
93  }
94  else
95  is >> num;
96 
97  return num;
98 }
99 
100 static std::istringstream&
101 extract_num (std::istringstream& is, double& num, bool& imag, bool& have_sign)
102 {
103  have_sign = imag = false;
104 
105  char c = is.peek ();
106 
107  // Skip leading spaces.
108  while (isspace (c))
109  {
110  is.get ();
111  c = is.peek ();
112  }
113 
114  bool negative = false;
115 
116  // Accept leading sign.
117  if (c == '+' || c == '-')
118  {
119  have_sign = true;
120  negative = c == '-';
121  is.get ();
122  c = is.peek ();
123  }
124 
125  // Skip spaces after sign.
126  while (isspace (c))
127  {
128  is.get ();
129  c = is.peek ();
130  }
131 
132  // Imaginary number (i*num or just i), or maybe 'inf'.
133  if (c == 'i')
134  {
135  // possible infinity.
136  is.get ();
137  c = is.peek ();
138 
139  if (is.eof ())
140  {
141  // just 'i' and string is finished. Return immediately.
142  imag = true;
143  num = negative ? -1.0 : 1.0;
144  return is;
145  }
146  else
147  {
148  if (std::tolower (c) != 'n')
149  imag = true;
150  is.unget ();
151  }
152  }
153  else if (c == 'j')
154  imag = true;
155 
156  // It's i*num or just i
157  if (imag)
158  {
159  is.get ();
160  c = is.peek ();
161  // Skip spaces after imaginary unit.
162  while (isspace (c))
163  {
164  is.get ();
165  c = is.peek ();
166  }
167 
168  if (c == '*')
169  {
170  // Multiplier follows, we extract it as a number.
171  is.get ();
172  num = single_num (is);
173  if (is.good ())
174  c = is.peek ();
175  }
176  else
177  num = 1.0;
178  }
179  else
180  {
181  // It's num, num*i, or numi.
182  num = single_num (is);
183  if (is.good ())
184  {
185  c = is.peek ();
186 
187  // Skip spaces after number.
188  while (isspace (c))
189  {
190  is.get ();
191  c = is.peek ();
192  }
193 
194  if (c == '*')
195  {
196  is.get ();
197  c = is.peek ();
198 
199  // Skip spaces after operator.
200  while (isspace (c))
201  {
202  is.get ();
203  c = is.peek ();
204  }
205 
206  if (is_imag_unit (c))
207  {
208  imag = true;
209  is.get ();
210  c = is.peek ();
211  }
212  else
213  is.setstate (std::ios::failbit); // indicate read has failed.
214  }
215  else if (is_imag_unit (c))
216  {
217  imag = true;
218  is.get ();
219  c = is.peek ();
220  }
221  }
222  }
223 
224  if (is.good ())
225  {
226  // Skip trailing spaces.
227  while (isspace (c))
228  {
229  is.get ();
230  c = is.peek ();
231  }
232  }
233 
234  if (negative)
235  num = -num;
236 
237  return is;
238 }
239 
240 static inline void
241 set_component (Complex& c, double num, bool imag)
242 {
243 #if defined (HAVE_CXX_COMPLEX_SETTERS)
244  if (imag)
245  c.imag (num);
246  else
247  c.real (num);
248 #elif defined (HAVE_CXX_COMPLEX_REFERENCE_ACCESSORS)
249  if (imag)
250  c.imag () = num;
251  else
252  c.real () = num;
253 #else
254  if (imag)
255  c = Complex (c.real (), num);
256  else
257  c = Complex (num, c.imag ());
258 #endif
259 }
260 
261 static Complex
262 str2double1 (const std::string& str_arg)
263 {
264  Complex val (0.0, 0.0);
265 
266  std::string str = str_arg;
267 
268  // FIXME: removing all commas doesn't allow actual parsing.
269  // Example: "1,23.45" is wrong, but passes Octave.
270  str.erase (std::remove (str.begin (), str.end(), ','), str.end ());
271  std::istringstream is (str);
272 
273  double num;
274  bool i1, i2, s1, s2;
275 
276  if (is.eof ())
277  val = octave_NaN;
278  else if (! extract_num (is, num, i1, s1))
279  val = octave_NaN;
280  else
281  {
282  set_component (val, num, i1);
283 
284  if (! is.eof ())
285  {
286  if (! extract_num (is, num, i2, s2) || i1 == i2 || ! s2)
287  val = octave_NaN;
288  else
289  set_component (val, num, i2);
290  }
291  }
292 
293  return val;
294 }
295 
296 DEFUN (str2double, args, ,
297  "-*- texinfo -*-\n\
298 @deftypefn {Built-in Function} {} str2double (@var{s})\n\
299 Convert a string to a real or complex number.\n\
300 \n\
301 The string must be in one of the following formats where\n\
302 a and b are real numbers and the complex unit is @qcode{'i'} or @qcode{'j'}:\n\
303 \n\
304 @itemize\n\
305 @item a + bi\n\
306 \n\
307 @item a + b*i\n\
308 \n\
309 @item a + i*b\n\
310 \n\
311 @item bi + a\n\
312 \n\
313 @item b*i + a\n\
314 \n\
315 @item i*b + a\n\
316 @end itemize\n\
317 \n\
318 If present, a and/or b are of the form @nospell{[+-]d[,.]d[[eE][+-]d]} where\n\
319 the brackets indicate optional arguments and @qcode{'d'} indicates zero or\n\
320 more digits. The special input values @code{Inf}, @code{NaN}, and @code{NA}\n\
321 are also accepted.\n\
322 \n\
323 @var{s} may be a character string, character matrix, or cell array.\n\
324 For character arrays the conversion is repeated for every row, and\n\
325 a double or complex array is returned. Empty rows in @var{s} are deleted\n\
326 and not returned in the numeric array. For cell arrays each character\n\
327 string element is processed and a double or complex array of the same\n\
328 dimensions as @var{s} is returned.\n\
329 \n\
330 For unconvertible scalar or character string input @code{str2double} returns\n\
331 a NaN@. Similarly, for character array input @code{str2double} returns a\n\
332 NaN for any row of @var{s} that could not be converted. For a cell array,\n\
333 @code{str2double} returns a NaN for any element of @var{s} for which\n\
334 conversion fails. Note that numeric elements in a mixed string/numeric\n\
335 cell array are not strings and the conversion will fail for these elements\n\
336 and return NaN.\n\
337 \n\
338 @code{str2double} can replace @code{str2num}, and it avoids the security\n\
339 risk of using @code{eval} on unknown data.\n\
340 @seealso{str2num}\n\
341 @end deftypefn")
342 {
343  octave_value retval;
344 
345  if (args.length () != 1)
346  print_usage ();
347  else if (args(0).is_string ())
348  {
349  if (args(0).rows () == 0 || args(0).columns () == 0)
350  {
351  retval = Matrix (1, 1, octave_NaN);
352  }
353  else if (args(0).rows () == 1 && args(0).ndims () == 2)
354  {
355  retval = str2double1 (args(0).string_value ());
356  }
357  else
358  {
359  const string_vector sv = args(0).all_strings ();
360  if (! error_state)
361  retval = sv.map<Complex> (str2double1);
362  }
363  }
364  else if (args(0).is_cell ())
365  {
366  const Cell cell = args(0).cell_value ();
367 
368  if (! error_state)
369  {
370  ComplexNDArray output (cell.dims (), octave_NaN);
371  for (octave_idx_type i = 0; i < cell.numel (); i++)
372  {
373  if (cell(i).is_string ())
374  output(i) = str2double1 (cell(i).string_value ());
375  }
376  retval = output;
377  }
378  }
379  else
380  retval = Matrix (1, 1, octave_NaN);
381 
382 
383  return retval;
384 }
385 
386 /*
387 %!assert (str2double ("1"), 1)
388 %!assert (str2double ("-.1e-5"), -1e-6)
389 %!assert (str2double (char ("1", "2 3", "4i")), [1; NaN; 4i])
390 %!assert (str2double ("1,222.5"), 1222.5)
391 %!assert (str2double ("i"), i)
392 %!assert (str2double ("2j"), 2i)
393 %!assert (str2double ("2 + j"), 2+j)
394 %!assert (str2double ("i*2 + 3"), 3+2i)
395 %!assert (str2double (".5*i + 3.5"), 3.5+0.5i)
396 %!assert (str2double ("1e-3 + i*.25"), 1e-3 + 0.25i)
397 %!assert (str2double (["2 + j";"1.25e-3";"-05"]), [2+i; 1.25e-3; -5])
398 %!assert (str2double ({"2 + j","1.25e-3","-05"}), [2+i, 1.25e-3, -5])
399 %!assert (str2double (1), NaN)
400 %!assert (str2double ("1 2 3 4"), NaN)
401 %!assert (str2double ("Hello World"), NaN)
402 %!assert (str2double ("NaN"), NaN)
403 %!assert (str2double ("NA"), NA)
404 %!assert (str2double ("Inf"), Inf)
405 %!assert (str2double ("iNF"), Inf)
406 %!assert (str2double ("-Inf"), -Inf)
407 %!assert (str2double ("Inf*i"), complex (0, Inf))
408 %!assert (str2double ("iNF*i"), complex (0, Inf))
409 %!assert (str2double ("NaN + Inf*i"), complex (NaN, Inf))
410 %!assert (str2double ("Inf - Inf*i"), complex (Inf, -Inf))
411 %!assert (str2double ("-i*NaN - Inf"), complex (-Inf, -NaN))
412 %!assert (str2double ({"abc", "4i"}), [NaN + 0i, 4i])
413 %!assert (str2double ({2, "4i"}), [NaN + 0i, 4i])
414 %!assert (str2double (zeros (3,1,2)), NaN)
415 %!assert (str2double (''), NaN)
416 %!assert (str2double ([]), NaN)
417 %!assert (str2double (char(zeros(3,0))), NaN)
418  */