str2double.cc

Go to the documentation of this file.
00001 /*
00002 
00003 Copyright (C) 2010-2012 Jaroslav Hajek
00004 Copyright (C) 2010 VZLU Prague
00005 
00006 This file is part of Octave.
00007 
00008 Octave is free software; you can redistribute it and/or modify it
00009 under the terms of the GNU General Public License as published by the
00010 Free Software Foundation; either version 3 of the License, or (at your
00011 option) any later version.
00012 
00013 Octave is distributed in the hope that it will be useful, but WITHOUT
00014 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00015 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
00016 for more details.
00017 
00018 You should have received a copy of the GNU General Public License
00019 along with Octave; see the file COPYING.  If not, see
00020 <http://www.gnu.org/licenses/>.
00021 
00022 */
00023 
00024 #ifdef HAVE_CONFIG_H
00025 #include <config.h>
00026 #endif
00027 
00028 #include <string>
00029 #include <cctype>
00030 #include <sstream>
00031 #include <algorithm>
00032 
00033 #include "lo-ieee.h"
00034 
00035 #include "Cell.h"
00036 #include "ov.h"
00037 #include "defun-dld.h"
00038 #include "gripes.h"
00039 #include "utils.h"
00040 
00041 static inline bool
00042 is_imag_unit (int c)
00043 { return c == 'i' || c == 'j'; }
00044 
00045 static std::istringstream&
00046 single_num (std::istringstream& is, double& num)
00047 {
00048   char c = is.peek ();
00049 
00050   // Skip spaces.
00051   while (isspace (c))
00052     {
00053       is.get ();
00054       c = is.peek ();
00055     }
00056 
00057   if (c == 'I')
00058     {
00059       // It's infinity.
00060       is.get ();
00061       char c1 = is.get (), c2 = is.get ();
00062       if (c1 == 'n' && c2 == 'f')
00063         {
00064           num = octave_Inf;
00065           is.peek (); // May sets EOF bit.
00066         }
00067       else
00068         is.setstate (std::ios::failbit); // indicate that read has failed.
00069     }
00070   else if (c == 'N')
00071     {
00072       // It's NA or NaN
00073       is.get ();
00074       char c1 = is.get ();
00075       if (c1 == 'A')
00076         {
00077           num = octave_NA;
00078           is.peek (); // May set EOF bit.
00079         }
00080       else
00081         {
00082           char c2 = is.get ();
00083           if (c1 == 'a' && c2 == 'N')
00084             {
00085               num = octave_NaN;
00086               is.peek (); // May set EOF bit.
00087             }
00088           else
00089             is.setstate (std::ios::failbit); // indicate that read has failed.
00090         }
00091     }
00092   else
00093     is >> num;
00094 
00095   return is;
00096 }
00097 
00098 static std::istringstream&
00099 extract_num (std::istringstream& is, double& num, bool& imag, bool& have_sign)
00100 {
00101   have_sign = imag = false;
00102 
00103   char c = is.peek ();
00104 
00105   // Skip leading spaces.
00106   while (isspace (c))
00107     {
00108       is.get ();
00109       c = is.peek ();
00110     }
00111 
00112   bool negative = false;
00113 
00114   // Accept leading sign.
00115   if (c == '+' || c == '-')
00116     {
00117       negative = c == '-';
00118       is.get ();
00119       c = is.peek ();
00120       have_sign = true;
00121     }
00122 
00123   // Skip spaces after sign.
00124   while (isspace (c))
00125     {
00126       is.get ();
00127       c = is.peek ();
00128     }
00129 
00130   // It's i*num or just i.
00131   if (is_imag_unit (c))
00132     {
00133       imag = true;
00134       is.get ();
00135       c = is.peek ();
00136 
00137       // Skip spaces after imaginary unit.
00138       while (isspace (c))
00139         {
00140           is.get ();
00141           c = is.peek ();
00142         }
00143 
00144       if (c == '*')
00145         {
00146           // Multiplier follows, we extract it as a number.
00147           is.get ();
00148           single_num (is, num);
00149           if (is.good ())
00150             c = is.peek ();
00151         }
00152       else
00153         num = 1.0;
00154     }
00155   else
00156     {
00157       // It's num, num*i, or numi.
00158       single_num (is, num);
00159       if (is.good ())
00160         {
00161           c = is.peek ();
00162 
00163           // Skip spaces after number.
00164           while (isspace (c))
00165             {
00166               is.get ();
00167               c = is.peek ();
00168             }
00169 
00170           if (c == '*')
00171             {
00172               is.get ();
00173               c = is.peek ();
00174 
00175               // Skip spaces after operator.
00176               while (isspace (c))
00177                 {
00178                   is.get ();
00179                   c = is.peek ();
00180                 }
00181 
00182               if (is_imag_unit (c))
00183                 {
00184                   imag = true;
00185                   is.get ();
00186                   c = is.peek ();
00187                 }
00188               else
00189                 is.setstate (std::ios::failbit); // indicate that read has failed.
00190             }
00191           else if (is_imag_unit (c))
00192             {
00193               imag = true;
00194               is.get ();
00195               c = is.peek ();
00196             }
00197         }
00198     }
00199 
00200   if (is.good ())
00201     {
00202       // Skip trailing spaces.
00203       while (isspace (c))
00204         {
00205           is.get ();
00206           c = is.peek ();
00207         }
00208     }
00209 
00210   if (negative)
00211     num = -num;
00212 
00213   return is;
00214 }
00215 
00216 static inline void
00217 set_component (Complex& c, double num, bool imag)
00218 {
00219 #if defined (HAVE_CXX_COMPLEX_SETTERS)
00220   if (imag)
00221     c.imag (num);
00222   else
00223     c.real (num);
00224 #elif defined (HAVE_CXX_COMPLEX_REFERENCE_ACCESSORS)
00225   if (imag)
00226     c.imag () = num;
00227   else
00228     c.real () = num;
00229 #else
00230   if (imag)
00231     c = Complex (c.real (), num);
00232   else
00233     c = Complex (num, c.imag ());
00234 #endif
00235 }
00236 
00237 static Complex
00238 str2double1 (const std::string& str_arg)
00239 {
00240   Complex val (0.0, 0.0);
00241 
00242   std::string str = str_arg;
00243 
00244   // FIXME -- removing all commas does too much...
00245   std::string::iterator se = str.end ();
00246   se = std::remove (str.begin (), se, ',');
00247   str.erase (se, str.end ());
00248   std::istringstream is (str);
00249 
00250   double num;
00251   bool i1, i2, s1, s2;
00252 
00253   if (is.eof ())
00254     val = octave_NaN;
00255   else if (! extract_num (is, num, i1, s1))
00256     val = octave_NaN;
00257   else
00258     {
00259       set_component (val, num, i1);
00260 
00261       if (! is.eof ())
00262         {
00263           if (! extract_num (is, num, i2, s2) || i1 == i2 || ! s2)
00264             val = octave_NaN;
00265           else
00266             set_component (val, num, i2);
00267         }
00268     }
00269 
00270   return val;
00271 }
00272 
00273 DEFUN_DLD (str2double, args, ,
00274   "-*- texinfo -*-\n\
00275 @deftypefn {Built-in Function} {} str2double (@var{s})\n\
00276 Convert a string to a real or complex number.\n\
00277 \n\
00278 The string must be in one of the following formats where\n\
00279 a and b are real numbers and the complex unit is 'i' or 'j':\n\
00280 \n\
00281 @itemize\n\
00282 @item a + bi\n\
00283 \n\
00284 @item a + b*i\n\
00285 \n\
00286 @item a + i*b\n\
00287 \n\
00288 @item bi + a\n\
00289 \n\
00290 @item b*i + a\n\
00291 \n\
00292 @item i*b + a\n\
00293 @end itemize\n\
00294 \n\
00295 If present, a and/or b are of the form @nospell{[+-]d[,.]d[[eE][+-]d]} where\n\
00296 the brackets indicate optional arguments and 'd' indicates zero or more\n\
00297 digits.  The special input values @code{Inf}, @code{NaN}, and @code{NA} are\n\
00298 also accepted.\n\
00299 \n\
00300 @var{s} may also be a character matrix, in which case the conversion is\n\
00301 repeated for each row.  Or @var{s} may be a cell array of strings, in which\n\
00302 case each element is converted and an array of the same dimensions is\n\
00303 returned.\n\
00304 \n\
00305 @code{str2double} returns NaN for elements of @var{s} which cannot be\n\
00306 converted.\n\
00307 \n\
00308 @code{str2double} can replace @code{str2num}, and it avoids the security\n\
00309 risk of using @code{eval} on unknown data.\n\
00310 @seealso{str2num}\n\
00311 @end deftypefn")
00312 {
00313   octave_value retval;
00314 
00315   if (args.length () != 1)
00316     print_usage ();
00317   else if (args(0).is_string ())
00318     {
00319       if (args(0).rows () == 1 && args(0).ndims () == 2)
00320         {
00321           retval = str2double1 (args(0).string_value ());
00322         }
00323       else
00324         {
00325           const string_vector sv = args(0).all_strings ();
00326           if (! error_state)
00327             retval = sv.map<Complex> (str2double1);
00328         }
00329     }
00330   else if (args(0).is_cell ())
00331     {
00332       const Cell cell = args(0).cell_value ();
00333 
00334       if (! error_state)
00335       {
00336         ComplexNDArray output (cell.dims (), octave_NaN);
00337         for (octave_idx_type i = 0; i < cell.numel (); i++)
00338         {
00339           if (cell(i).is_string ())
00340             output(i) = str2double1 (cell(i).string_value ());
00341         }
00342         retval = output;
00343       }
00344     }
00345   else
00346     retval = NDArray (args(0).dims (), octave_NaN);
00347 
00348 
00349   return retval;
00350 }
00351 
00352 /*
00353 
00354 %!assert (str2double ("1"), 1)
00355 %!assert (str2double ("-.1e-5"), -1e-6)
00356 %!assert (str2double (char ("1", "2 3", "4i")), [1; NaN; 4i]);
00357 %!assert (str2double ("-.1e-5"), -1e-6)
00358 %!assert (str2double ("1,222.5"), 1222.5)
00359 %!assert (str2double ("i"), i)
00360 %!assert (str2double ("2j"), 2i)
00361 %!assert (str2double ("2 + j"), 2+j)
00362 %!assert (str2double ("i*2 + 3"), 3+2i)
00363 %!assert (str2double (".5*i + 3.5"), 3.5+0.5i)
00364 %!assert (str2double ("1e-3 + i*.25"), 1e-3 + 0.25i)
00365 %!assert (str2double (["2 + j";"1.25e-3";"-05"]), [2+i; 1.25e-3; -5])
00366 %!assert (str2double ({"2 + j","1.25e-3","-05"}), [2+i, 1.25e-3, -5])
00367 %!assert (str2double (1), NaN)
00368 %!assert (str2double ("1 2 3 4"), NaN)
00369 %!assert (str2double ("Hello World"), NaN)
00370 %!assert (str2double ("NaN"), NaN)
00371 %!assert (str2double ("NA"), NA)
00372 %!assert (str2double ("Inf"), Inf)
00373 %!assert (str2double ("-Inf"), -Inf)
00374 %!assert (str2double ("Inf*i"), complex (0, Inf))
00375 %!assert (str2double ("NaN + Inf*i"), complex (NaN, Inf))
00376 %!assert (str2double ("Inf - Inf*i"), complex (Inf, -Inf))
00377 %!assert (str2double ("-i*NaN - Inf"), complex (-Inf, -NaN))
00378 %!assert (str2double ({"abc", "4i"}), [NaN + 0i, 4i])
00379 %!assert (str2double ({2, "4i"}), [NaN + 0i, 4i])
00380 %!assert (str2double (zeros(3,1,2)), NaN (3,1,2))
00381 
00382 */
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Defines