GNU Octave  4.2.1
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-2017 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 #if defined (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 "errwarn.h"
39 #include "utils.h"
40 
41 static inline bool
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  {
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  {
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 ())
279  else if (! extract_num (is, num, i1, s1))
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)
289  else
290  set_component (val, num, i2);
291  }
292  }
293 
294  return val;
295 }
296 
297 DEFUN (str2double, args, ,
298  doc: /* -*- texinfo -*-
299 @deftypefn {} {} str2double (@var{s})
300 Convert a string to a real or complex number.
301 
302 The string must be in one of the following formats where a and b are real
303 numbers and the complex unit is @qcode{'i'} or @qcode{'j'}:
304 
305 @itemize
306 @item a + bi
307 
308 @item a + b*i
309 
310 @item a + i*b
311 
312 @item bi + a
313 
314 @item b*i + a
315 
316 @item i*b + a
317 @end itemize
318 
319 If present, a and/or b are of the form @nospell{[+-]d[,.]d[[eE][+-]d]} where
320 the brackets indicate optional arguments and @qcode{'d'} indicates zero or
321 more digits. The special input values @code{Inf}, @code{NaN}, and @code{NA}
322 are also accepted.
323 
324 @var{s} may be a character string, character matrix, or cell array. For
325 character arrays the conversion is repeated for every row, and a double or
326 complex array is returned. Empty rows in @var{s} are deleted and not
327 returned in the numeric array. For cell arrays each character string
328 element is processed and a double or complex array of the same dimensions as
329 @var{s} is returned.
330 
331 For unconvertible scalar or character string input @code{str2double} returns
332 a NaN@. Similarly, for character array input @code{str2double} returns a
333 NaN for any row of @var{s} that could not be converted. For a cell array,
334 @code{str2double} returns a NaN for any element of @var{s} for which
335 conversion fails. Note that numeric elements in a mixed string/numeric
336 cell array are not strings and the conversion will fail for these elements
337 and return NaN.
338 
339 @code{str2double} can replace @code{str2num}, and it avoids the security
340 risk of using @code{eval} on unknown data.
341 @seealso{str2num}
342 @end deftypefn */)
343 {
344  if (args.length () != 1)
346 
348 
349  if (args(0).is_string ())
350  {
351  if (args(0).rows () == 0 || args(0).columns () == 0)
352  retval = Matrix (1, 1, octave::numeric_limits<double>::NaN ());
353  else if (args(0).rows () == 1 && args(0).ndims () == 2)
354  retval = str2double1 (args(0).string_value ());
355  else
356  {
357  const string_vector sv = args(0).string_vector_value ();
358 
359  retval = sv.map<Complex> (str2double1);
360  }
361  }
362  else if (args(0).is_cell ())
363  {
364  const Cell cell = args(0).cell_value ();
365 
367 
368  for (octave_idx_type i = 0; i < cell.numel (); i++)
369  {
370  if (cell(i).is_string ())
371  output(i) = str2double1 (cell(i).string_value ());
372  }
373  retval = output;
374  }
375  else
376  retval = Matrix (1, 1, octave::numeric_limits<double>::NaN ());
377 
378  return retval;
379 }
380 
381 /*
382 %!assert (str2double ("1"), 1)
383 %!assert (str2double ("-.1e-5"), -1e-6)
384 %!assert (str2double (char ("1", "2 3", "4i")), [1; NaN; 4i])
385 %!assert (str2double ("1,222.5"), 1222.5)
386 %!assert (str2double ("i"), i)
387 %!assert (str2double ("2j"), 2i)
388 %!assert (str2double ("2 + j"), 2+j)
389 %!assert (str2double ("i*2 + 3"), 3+2i)
390 %!assert (str2double (".5*i + 3.5"), 3.5+0.5i)
391 %!assert (str2double ("1e-3 + i*.25"), 1e-3 + 0.25i)
392 %!assert (str2double (["2 + j";"1.25e-3";"-05"]), [2+i; 1.25e-3; -5])
393 %!assert (str2double ({"2 + j","1.25e-3","-05"}), [2+i, 1.25e-3, -5])
394 %!assert (str2double (1), NaN)
395 %!assert (str2double ("1 2 3 4"), NaN)
396 %!assert (str2double ("Hello World"), NaN)
397 %!assert (str2double ("NaN"), NaN)
398 %!assert (str2double ("NA"), NA)
399 %!assert (str2double ("Inf"), Inf)
400 %!assert (str2double ("iNF"), Inf)
401 %!assert (str2double ("-Inf"), -Inf)
402 %!assert (str2double ("Inf*i"), complex (0, Inf))
403 %!assert (str2double ("iNF*i"), complex (0, Inf))
404 %!assert (str2double ("NaN + Inf*i"), complex (NaN, Inf))
405 %!assert (str2double ("Inf - Inf*i"), complex (Inf, -Inf))
406 %!assert (str2double ("-i*NaN - Inf"), complex (-Inf, -NaN))
407 %!assert (str2double ({"abc", "4i"}), [NaN + 0i, 4i])
408 %!assert (str2double ({2, "4i"}), [NaN + 0i, 4i])
409 %!assert (str2double (zeros (3,1,2)), NaN)
410 %!assert (str2double (''), NaN)
411 %!assert (str2double ([]), NaN)
412 %!assert (str2double (char(zeros(3,0))), NaN)
413 */
octave_value retval
Definition: str2double.cc:347
static Complex str2double1(const std::string &str_arg)
Definition: str2double.cc:263
Definition: Cell.h:37
OCTINTERP_API void print_usage(void)
Definition: defun.cc:52
octave_idx_type numel(void) const
Number of elements in the array.
Definition: Array.h:363
identity matrix If supplied two scalar respectively For allows like xample val
Definition: data.cc:5068
s2
Definition: sub2ind.cc:107
#define DEFUN(name, args_name, nargout_name, doc)
Definition: defun.h:46
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
JNIEnv void * args
Definition: ov-java.cc:67
const dim_vector & dims(void) const
Return a const-reference so that dims ()(i) works efficiently.
Definition: Array.h:439
static double single_num(std::istringstream &is)
Definition: str2double.cc:46
Array< U > map(F fcn) const
Apply function fcn to each element of the Array.
Definition: Array.h:760
std::string string_value(bool force=false) const
Definition: ov.h:908
std::string str
Definition: hash.cc:118
#define octave_NA
Definition: lo-ieee.h:36
Definition: dMatrix.h:37
the sparsity preserving column transformation such that that defines the pivoting threshold can be given in which case it defines the c
Definition: lu.cc:138
#define Inf
Definition: Faddeeva.cc:247
=val(i)}if ode{val(i)}occurs in table i
Definition: lookup.cc:239
static void set_component(Complex &c, double num, bool imag)
Definition: str2double.cc:242
OCTAVE_EXPORT octave_value_list or N dimensional array whose elements are all equal to the IEEE symbol NaN(Not a Number).NaN is the result of operations which do not produce a well defined 0 result.Common operations which produce a NaN are arithmetic with infinity ex($\infty-\infty $)
ColumnVector imag(const ComplexColumnVector &a)
Definition: dColVector.cc:142
std::complex< double > Complex
Definition: oct-cmplx.h:31
write the output to stdout if nargout is
Definition: load-save.cc:1576
If this string is the system will ring the terminal sometimes it is useful to be able to print the original representation of the string
Definition: utils.cc:854