GNU Octave  4.0.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-2015 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 = 0.0;
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 ();
64  char c2 = is.get ();
65  if (std::tolower (c1) == 'n' && std::tolower (c2) == 'f')
66  {
67  num = octave_Inf;
68  is.peek (); // May set EOF bit.
69  }
70  else
71  is.setstate (std::ios::failbit); // indicate that read has failed.
72  }
73  else if (c == 'N')
74  {
75  // It's NA or NaN
76  is.get ();
77  char c1 = is.get ();
78  if (c1 == 'A')
79  {
80  num = octave_NA;
81  is.peek (); // May set EOF bit.
82  }
83  else
84  {
85  char c2 = is.get ();
86  if (c1 == 'a' && c2 == 'N')
87  {
88  num = octave_NaN;
89  is.peek (); // May set EOF bit.
90  }
91  else
92  is.setstate (std::ios::failbit); // indicate that read has failed.
93  }
94  }
95  else
96  is >> num;
97 
98  return num;
99 }
100 
101 static std::istringstream&
102 extract_num (std::istringstream& is, double& num, bool& imag, bool& have_sign)
103 {
104  have_sign = imag = false;
105 
106  char c = is.peek ();
107 
108  // Skip leading spaces.
109  while (isspace (c))
110  {
111  is.get ();
112  c = is.peek ();
113  }
114 
115  bool negative = false;
116 
117  // Accept leading sign.
118  if (c == '+' || c == '-')
119  {
120  have_sign = true;
121  negative = c == '-';
122  is.get ();
123  c = is.peek ();
124  }
125 
126  // Skip spaces after sign.
127  while (isspace (c))
128  {
129  is.get ();
130  c = is.peek ();
131  }
132 
133  // Imaginary number (i*num or just i), or maybe 'inf'.
134  if (c == 'i')
135  {
136  // possible infinity.
137  is.get ();
138  c = is.peek ();
139 
140  if (is.eof ())
141  {
142  // just 'i' and string is finished. Return immediately.
143  imag = true;
144  num = negative ? -1.0 : 1.0;
145  return is;
146  }
147  else
148  {
149  if (std::tolower (c) != 'n')
150  imag = true;
151  is.unget ();
152  }
153  }
154  else if (c == 'j')
155  imag = true;
156 
157  // It's i*num or just i
158  if (imag)
159  {
160  is.get ();
161  c = is.peek ();
162  // Skip spaces after imaginary unit.
163  while (isspace (c))
164  {
165  is.get ();
166  c = is.peek ();
167  }
168 
169  if (c == '*')
170  {
171  // Multiplier follows, we extract it as a number.
172  is.get ();
173  num = single_num (is);
174  if (is.good ())
175  c = is.peek ();
176  }
177  else
178  num = 1.0;
179  }
180  else
181  {
182  // It's num, num*i, or numi.
183  num = single_num (is);
184  if (is.good ())
185  {
186  c = is.peek ();
187 
188  // Skip spaces after number.
189  while (isspace (c))
190  {
191  is.get ();
192  c = is.peek ();
193  }
194 
195  if (c == '*')
196  {
197  is.get ();
198  c = is.peek ();
199 
200  // Skip spaces after operator.
201  while (isspace (c))
202  {
203  is.get ();
204  c = is.peek ();
205  }
206 
207  if (is_imag_unit (c))
208  {
209  imag = true;
210  is.get ();
211  c = is.peek ();
212  }
213  else
214  is.setstate (std::ios::failbit); // indicate read has failed.
215  }
216  else if (is_imag_unit (c))
217  {
218  imag = true;
219  is.get ();
220  c = is.peek ();
221  }
222  }
223  }
224 
225  if (is.good ())
226  {
227  // Skip trailing spaces.
228  while (isspace (c))
229  {
230  is.get ();
231  c = is.peek ();
232  }
233  }
234 
235  if (negative)
236  num = -num;
237 
238  return is;
239 }
240 
241 static inline void
242 set_component (Complex& c, double num, bool imag)
243 {
244 #if defined (HAVE_CXX_COMPLEX_SETTERS)
245  if (imag)
246  c.imag (num);
247  else
248  c.real (num);
249 #elif defined (HAVE_CXX_COMPLEX_REFERENCE_ACCESSORS)
250  if (imag)
251  c.imag () = num;
252  else
253  c.real () = num;
254 #else
255  if (imag)
256  c = Complex (c.real (), num);
257  else
258  c = Complex (num, c.imag ());
259 #endif
260 }
261 
262 static Complex
263 str2double1 (const std::string& str_arg)
264 {
265  Complex val (0.0, 0.0);
266 
267  std::string str = str_arg;
268 
269  // FIXME: removing all commas doesn't allow actual parsing.
270  // Example: "1,23.45" is wrong, but passes Octave.
271  str.erase (std::remove (str.begin (), str.end(), ','), str.end ());
272  std::istringstream is (str);
273 
274  double num;
275  bool i1, i2, s1, s2;
276 
277  if (is.eof ())
278  val = octave_NaN;
279  else if (! extract_num (is, num, i1, s1))
280  val = octave_NaN;
281  else
282  {
283  set_component (val, num, i1);
284 
285  if (! is.eof ())
286  {
287  if (! extract_num (is, num, i2, s2) || i1 == i2 || ! s2)
288  val = octave_NaN;
289  else
290  set_component (val, num, i2);
291  }
292  }
293 
294  return val;
295 }
296 
297 DEFUN (str2double, args, ,
298  "-*- texinfo -*-\n\
299 @deftypefn {Built-in Function} {} str2double (@var{s})\n\
300 Convert a string to a real or complex number.\n\
301 \n\
302 The string must be in one of the following formats where a and b are real\n\
303 numbers and the complex unit is @qcode{'i'} or @qcode{'j'}:\n\
304 \n\
305 @itemize\n\
306 @item a + bi\n\
307 \n\
308 @item a + b*i\n\
309 \n\
310 @item a + i*b\n\
311 \n\
312 @item bi + a\n\
313 \n\
314 @item b*i + a\n\
315 \n\
316 @item i*b + a\n\
317 @end itemize\n\
318 \n\
319 If present, a and/or b are of the form @nospell{[+-]d[,.]d[[eE][+-]d]} where\n\
320 the brackets indicate optional arguments and @qcode{'d'} indicates zero or\n\
321 more digits. The special input values @code{Inf}, @code{NaN}, and @code{NA}\n\
322 are also accepted.\n\
323 \n\
324 @var{s} may be a character string, character matrix, or cell array. For\n\
325 character arrays the conversion is repeated for every row, and a double or\n\
326 complex array is returned. Empty rows in @var{s} are deleted and not\n\
327 returned in the numeric array. For cell arrays each character string\n\
328 element is processed and a double or complex array of the same dimensions as\n\
329 @var{s} is returned.\n\
330 \n\
331 For unconvertible scalar or character string input @code{str2double} returns\n\
332 a NaN@. Similarly, for character array input @code{str2double} returns a\n\
333 NaN for any row of @var{s} that could not be converted. For a cell array,\n\
334 @code{str2double} returns a NaN for any element of @var{s} for which\n\
335 conversion fails. Note that numeric elements in a mixed string/numeric\n\
336 cell array are not strings and the conversion will fail for these elements\n\
337 and return NaN.\n\
338 \n\
339 @code{str2double} can replace @code{str2num}, and it avoids the security\n\
340 risk of using @code{eval} on unknown data.\n\
341 @seealso{str2num}\n\
342 @end deftypefn")
343 {
344  octave_value retval;
345 
346  if (args.length () != 1)
347  print_usage ();
348  else if (args(0).is_string ())
349  {
350  if (args(0).rows () == 0 || args(0).columns () == 0)
351  {
352  retval = Matrix (1, 1, octave_NaN);
353  }
354  else if (args(0).rows () == 1 && args(0).ndims () == 2)
355  {
356  retval = str2double1 (args(0).string_value ());
357  }
358  else
359  {
360  const string_vector sv = args(0).all_strings ();
361  if (! error_state)
362  retval = sv.map<Complex> (str2double1);
363  }
364  }
365  else if (args(0).is_cell ())
366  {
367  const Cell cell = args(0).cell_value ();
368 
369  if (! error_state)
370  {
371  ComplexNDArray output (cell.dims (), octave_NaN);
372  for (octave_idx_type i = 0; i < cell.numel (); i++)
373  {
374  if (cell(i).is_string ())
375  output(i) = str2double1 (cell(i).string_value ());
376  }
377  retval = output;
378  }
379  }
380  else
381  retval = Matrix (1, 1, octave_NaN);
382 
383 
384  return retval;
385 }
386 
387 /*
388 %!assert (str2double ("1"), 1)
389 %!assert (str2double ("-.1e-5"), -1e-6)
390 %!assert (str2double (char ("1", "2 3", "4i")), [1; NaN; 4i])
391 %!assert (str2double ("1,222.5"), 1222.5)
392 %!assert (str2double ("i"), i)
393 %!assert (str2double ("2j"), 2i)
394 %!assert (str2double ("2 + j"), 2+j)
395 %!assert (str2double ("i*2 + 3"), 3+2i)
396 %!assert (str2double (".5*i + 3.5"), 3.5+0.5i)
397 %!assert (str2double ("1e-3 + i*.25"), 1e-3 + 0.25i)
398 %!assert (str2double (["2 + j";"1.25e-3";"-05"]), [2+i; 1.25e-3; -5])
399 %!assert (str2double ({"2 + j","1.25e-3","-05"}), [2+i, 1.25e-3, -5])
400 %!assert (str2double (1), NaN)
401 %!assert (str2double ("1 2 3 4"), NaN)
402 %!assert (str2double ("Hello World"), NaN)
403 %!assert (str2double ("NaN"), NaN)
404 %!assert (str2double ("NA"), NA)
405 %!assert (str2double ("Inf"), Inf)
406 %!assert (str2double ("iNF"), Inf)
407 %!assert (str2double ("-Inf"), -Inf)
408 %!assert (str2double ("Inf*i"), complex (0, Inf))
409 %!assert (str2double ("iNF*i"), complex (0, Inf))
410 %!assert (str2double ("NaN + Inf*i"), complex (NaN, Inf))
411 %!assert (str2double ("Inf - Inf*i"), complex (Inf, -Inf))
412 %!assert (str2double ("-i*NaN - Inf"), complex (-Inf, -NaN))
413 %!assert (str2double ({"abc", "4i"}), [NaN + 0i, 4i])
414 %!assert (str2double ({2, "4i"}), [NaN + 0i, 4i])
415 %!assert (str2double (zeros (3,1,2)), NaN)
416 %!assert (str2double (''), NaN)
417 %!assert (str2double ([]), NaN)
418 %!assert (str2double (char(zeros(3,0))), NaN)
419  */
static Complex str2double1(const std::string &str_arg)
Definition: str2double.cc:263
Definition: Cell.h:35
int ndims(void) const
Definition: ov.h:479
octave_idx_type rows(void) const
Definition: ov.h:473
OCTINTERP_API void print_usage(void)
Definition: defun.cc:51
octave_idx_type numel(void) const
Number of elements in the array.
Definition: Array.h:275
#define DEFUN(name, args_name, nargout_name, doc)
Definition: defun.h:44
static bool is_imag_unit(int c)
Definition: str2double.cc:42
static std::istringstream & extract_num(std::istringstream &is, double &num, bool &imag, bool &have_sign)
Definition: str2double.cc:102
const dim_vector & dims(void) const
Return a const-reference so that dims ()(i) works efficiently.
Definition: Array.h:337
static double single_num(std::istringstream &is)
Definition: str2double.cc:46
#define octave_Inf
Definition: lo-ieee.h:31
Array< U > map(F fcn) const
Apply function fcn to each element of the Array.
Definition: Array.h:659
std::string string_value(bool force=false) const
Definition: ov.h:897
int error_state
Definition: error.cc:101
#define octave_NA
Definition: lo-ieee.h:34
Definition: dMatrix.h:35
#define octave_NaN
Definition: lo-ieee.h:37
static void set_component(Complex &c, double num, bool imag)
Definition: str2double.cc:242
ColumnVector imag(const ComplexColumnVector &a)
Definition: dColVector.cc:162
static MArray< double > const octave_idx_type const octave_idx_type octave_idx_type octave_idx_type octave_idx_type c1
std::complex< double > Complex
Definition: oct-cmplx.h:29