GNU Octave  4.4.1
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
str2double.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 2010-2018 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
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
12 
13 Octave is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License 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 <https://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)
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).iscell ())
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
377 
378  return retval;
379 }
380 
381 /*
382 %!assert (str2double ("1"), 1)
383 %!assert (str2double ("-.1e-5"), -1e-6)
384 %!testif ; ! ismac ()
385 %! assert (str2double (char ("1", "2 3", "4i")), [1; NaN; 4i]);
386 %!xtest <47413>
387 %! ## Same test code as above, but intended only for test statistics on Mac.
388 %! if (! ismac ()), return; endif
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 (char ("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 %!testif ; ! ismac ()
413 %! assert (str2double ({"abc", "4i"}), [NaN + 0i, 4i]);
414 %!xtest <47413>
415 %! if (! ismac ()), return; endif
416 %! assert (str2double ({"abc", "4i"}), [NaN + 0i, 4i]);
417 %!testif ; ! ismac ()
418 %! assert (str2double ({2, "4i"}), [NaN + 0i, 4i])
419 %!xtest <47413>
420 %! if (! ismac ()), return; endif
421 %! assert (str2double ({2, "4i"}), [NaN + 0i, 4i])
422 %!assert (str2double (zeros (3,1,2)), NaN)
423 %!assert (str2double (''), NaN)
424 %!assert (str2double ([]), NaN)
425 %!assert (str2double (char(zeros(3,0))), NaN)
426 */
octave_value retval
Definition: str2double.cc:347
static Complex str2double1(const std::string &str_arg)
Definition: str2double.cc:263
Definition: Cell.h:37
std::string string_value(bool force=false) const
Definition: ov.h:955
OCTINTERP_API void print_usage(void)
Definition: defun.cc:54
identity matrix If supplied two scalar respectively For allows like xample val
Definition: data.cc:4986
s2
Definition: sub2ind.cc:107
#define DEFUN(name, args_name, nargout_name, doc)
Macro to define a builtin function.
Definition: defun.h:53
const dim_vector & dims(void) const
Return a const-reference so that dims ()(i) works efficiently.
Definition: Array.h:442
static bool is_imag_unit(int c)
Definition: str2double.cc:42
nd example oindent opens the file binary numeric values will be read assuming they are stored in IEEE format with the least significant bit and then converted to the native representation Opening a file that is already open simply opens it again and returns a separate file id It is not an error to open a file several though writing to the same file through several different file ids may produce unexpected results The possible values of text mode reading and writing automatically converts linefeeds to the appropriate line end character for the you may append a you must also open the file in binary mode The parameter conversions are currently only supported for and permissions will be set to and then everything is written in a single operation This is very efficient and improves performance c
Definition: file-io.cc:587
static std::istringstream & extract_num(std::istringstream &is, double &num, bool &imag, bool &have_sign)
Definition: str2double.cc:102
static double single_num(std::istringstream &is)
Definition: str2double.cc:46
std::string str
Definition: hash.cc:118
#define octave_NA
Definition: lo-ieee.h:38
Definition: dMatrix.h:36
#define Inf
Definition: Faddeeva.cc:247
Array< U > map(F fcn) const
Apply function fcn to each element of the Array<T>.
Definition: Array.h:764
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:141
for i
Definition: data.cc:5264
std::complex< double > Complex
Definition: oct-cmplx.h:31
octave_idx_type numel(void) const
Number of elements in the array.
Definition: Array.h:366
write the output to stdout if nargout is
Definition: load-save.cc:1612
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:888