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
dlmread.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 2008-2017 Jonathan Stickel
4 Copyright (C) 2010 Jaroslav Hajek
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 // Adapted from previous version of dlmread.occ as authored by Kai
25 // Habel, but core code has been completely re-written.
26 
27 #if defined (HAVE_CONFIG_H)
28 # include "config.h"
29 #endif
30 
31 #include <cctype>
32 #include <fstream>
33 #include <limits>
34 
35 #include "file-ops.h"
36 #include "lo-ieee.h"
37 
38 #include "defun.h"
39 #include "oct-stream.h"
40 #include "error.h"
41 #include "ovl.h"
42 #include "utils.h"
43 
44 static const octave_idx_type idx_max =
46 
47 static bool
49 {
50  bool stat = false;
51 
52  if (is.peek () == std::istream::traits_type::eof ())
53  stat = true;
54  else
55  {
56  if (::isalpha (is.peek ()))
57  {
58  col = 0;
59  while (is && ::isalpha (is.peek ()))
60  {
61  char ch = is.get ();
62  col *= 26;
63  if (ch >= 'a')
64  col += ch - 'a' + 1;
65  else
66  col += ch - 'A' + 1;
67  }
68  col--;
69 
70  if (is)
71  {
72  is >> row;
73  row--;
74  if (is)
75  stat = true;
76  }
77  }
78  }
79 
80  return stat;
81 }
82 
83 static bool
84 parse_range_spec (const octave_value& range_spec,
87 {
88  bool stat = true;
89 
90  if (range_spec.is_string ())
91  {
92  std::istringstream is (range_spec.string_value ());
93  char ch = is.peek ();
94 
95  if (ch == '.' || ch == ':')
96  {
97  rlo = 0;
98  clo = 0;
99  ch = is.get ();
100  if (ch == '.')
101  {
102  ch = is.get ();
103  if (ch != '.')
104  stat = false;
105  }
106  }
107  else
108  {
109  stat = read_cell_spec (is, rlo, clo);
110 
111  if (stat)
112  {
113  ch = is.peek ();
114 
115  if (ch == '.' || ch == ':')
116  {
117  ch = is.get ();
118  if (ch == '.')
119  {
120  ch = is.get ();
121  if (! is || ch != '.')
122  stat = false;
123  }
124 
125  rup = idx_max - 1;
126  cup = idx_max - 1;
127  }
128  else
129  {
130  rup = rlo;
131  cup = clo;
132  if (! is || ! is.eof ())
133  stat = false;
134  }
135  }
136  }
137 
138  if (stat && is && ! is.eof ())
139  stat = read_cell_spec (is, rup, cup);
140 
141  if (! is || ! is.eof ())
142  stat = false;
143  }
144  else if (range_spec.is_real_matrix () && range_spec.numel () == 4)
145  {
146  ColumnVector range(range_spec.vector_value ());
147  // double --> unsigned int
148  rlo = static_cast<octave_idx_type> (range(0));
149  clo = static_cast<octave_idx_type> (range(1));
150  rup = static_cast<octave_idx_type> (range(2));
151  cup = static_cast<octave_idx_type> (range(3));
152  }
153  else
154  stat = false;
155 
156  return stat;
157 }
158 
159 DEFUN (dlmread, args, ,
160  doc: /* -*- texinfo -*-
161 @deftypefn {} {@var{data} =} dlmread (@var{file})
162 @deftypefnx {} {@var{data} =} dlmread (@var{file}, @var{sep})
163 @deftypefnx {} {@var{data} =} dlmread (@var{file}, @var{sep}, @var{r0}, @var{c0})
164 @deftypefnx {} {@var{data} =} dlmread (@var{file}, @var{sep}, @var{range})
165 @deftypefnx {} {@var{data} =} dlmread (@dots{}, "emptyvalue", @var{EMPTYVAL})
166 Read numeric data from the text file @var{file} which uses the delimiter
167 @var{sep} between data values.
168 
169 If @var{sep} is not defined the separator between fields is determined from
170 the file itself.
171 
172 The optional scalar arguments @var{r0} and @var{c0} define the starting row
173 and column of the data to be read. These values are indexed from zero,
174 i.e., the first data row corresponds to an index of zero.
175 
176 The @var{range} parameter specifies exactly which data elements are read.
177 The first form of the parameter is a 4-element vector containing the upper
178 left and lower right corners @code{[@var{R0},@var{C0},@var{R1},@var{C1}]}
179 where the indices are zero-based. Alternatively, a spreadsheet style
180 form such as @qcode{"A2..Q15"} or @qcode{"T1:AA5"} can be used. The
181 lowest alphabetical index @qcode{'A'} refers to the first column. The
182 lowest row index is 1.
183 
184 @var{file} should be a filename or a file id given by @code{fopen}. In the
185 latter case, the file is read until end of file is reached.
186 
187 The @qcode{"emptyvalue"} option may be used to specify the value used to
188 fill empty fields. The default is zero. Note that any non-numeric values,
189 such as text, are also replaced by the @qcode{"emptyvalue"}.
190 @seealso{csvread, textscan, textread, dlmwrite}
191 @end deftypefn */)
192 {
193  int nargin = args.length ();
194 
195  double empty_value = 0.0;
196 
197  if (nargin > 2 && args(nargin-2).is_string ()
198  && args(nargin-2).string_value () == "emptyvalue")
199  {
200  empty_value = args(nargin-1).double_value ();
201 
202  nargin -= 2;
203  }
204 
205  if (nargin < 1 || nargin > 4)
206  print_usage ();
207 
208  std::istream *input = 0;
209  std::ifstream input_file;
210 
211  if (args(0).is_string ())
212  {
213  // Filename.
214  std::string fname (args(0).string_value ());
215 
217 
218  tname = find_data_file_in_load_path ("dlmread", tname);
219 
220  input_file.open (tname.c_str (), std::ios::in);
221 
222  if (! input_file)
223  error ("dlmread: unable to open file '%s'", fname.c_str ());
224 
225  input = &input_file;
226  }
227  else if (args(0).is_scalar_type ())
228  {
230 
231  input = is.input_stream ();
232 
233  if (! input)
234  error ("dlmread: stream FILE not open for input");
235  }
236  else
237  error ("dlmread: FILE argument must be a string or file id");
238 
239  // Set default separator.
240  std::string sep;
241  if (nargin > 1)
242  {
243  if (args(1).is_sq_string ())
244  sep = do_string_escapes (args(1).string_value ());
245  else
246  sep = args(1).string_value ();
247  }
248 
249  // Take a subset if a range was given.
250  octave_idx_type r0 = 0;
251  octave_idx_type c0 = 0;
252  octave_idx_type r1 = idx_max-1;
253  octave_idx_type c1 = idx_max-1;
254  if (nargin > 2)
255  {
256  if (nargin == 3)
257  {
258  if (! parse_range_spec (args(2), r0, c0, r1, c1))
259  error ("dlmread: error parsing RANGE");
260  }
261  else if (nargin == 4)
262  {
263  r0 = args(2).idx_type_value ();
264  c0 = args(3).idx_type_value ();
265  }
266 
267  if (r0 < 0 || c0 < 0)
268  error ("dlmread: left & top must be positive");
269  }
270 
271  octave_idx_type i = 0;
272  octave_idx_type j = 0;
273  octave_idx_type r = 1;
274  octave_idx_type c = 1;
275  octave_idx_type rmax = 0;
276  octave_idx_type cmax = 0;
277 
278  Matrix rdata;
279  ComplexMatrix cdata;
280 
281  bool iscmplx = false;
282  bool sepflag = false;
283 
285 
286  // Skip the r0 leading lines as these might be a header.
287  for (octave_idx_type m = 0; m < r0; m++)
288  getline (*input, line);
289  r1 -= r0;
290 
291  std::istringstream tmp_stream;
292 
293  // Read in the data one field at a time, growing the data matrix
294  // as needed.
295  while (getline (*input, line))
296  {
297  // Skip blank lines for compatibility.
298  if (line.find_first_not_of (" \t") == std::string::npos)
299  continue;
300 
301  // To be compatible with matlab, blank separator should
302  // correspond to whitespace as delimter.
303  if (! sep.length ())
304  {
305  size_t n = line.find_first_of (",:; \t",
306  line.find_first_of ("0123456789"));
307  if (n == std::string::npos)
308  {
309  sep = " \t";
310  sepflag = true;
311  }
312  else
313  {
314  char ch = line.at (n);
315 
316  switch (line.at (n))
317  {
318  case ' ':
319  case '\t':
320  sepflag = true;
321  sep = " \t";
322  break;
323 
324  default:
325  sep = ch;
326  break;
327  }
328  }
329  }
330 
331  if (cmax == 0)
332  {
333  // Try to estimate the number of columns. Skip leading
334  // whitespace.
335  size_t pos1 = line.find_first_not_of (" \t");
336  do
337  {
338  size_t pos2 = line.find_first_of (sep, pos1);
339 
340  if (sepflag && pos2 != std::string::npos)
341  // Treat consecutive separators as one.
342  {
343  pos2 = line.find_first_not_of (sep, pos2);
344  if (pos2 != std::string::npos)
345  pos2 -= 1;
346  else
347  pos2 = line.length () - 1;
348  }
349 
350  cmax++;
351 
352  if (pos2 != std::string::npos)
353  pos1 = pos2 + 1;
354  else
355  pos1 = std::string::npos;
356 
357  }
358  while (pos1 != std::string::npos);
359 
360  if (iscmplx)
361  cdata.resize (rmax, cmax);
362  else
363  rdata.resize (rmax, cmax);
364  }
365 
366  r = (r > i + 1 ? r : i + 1);
367  j = 0;
368  // Skip leading whitespace.
369  size_t pos1 = line.find_first_not_of (" \t");
370  do
371  {
372  octave_quit ();
373 
374  size_t pos2 = line.find_first_of (sep, pos1);
375  std::string str = line.substr (pos1, pos2 - pos1);
376 
377  if (sepflag && pos2 != std::string::npos)
378  // Treat consecutive separators as one.
379  pos2 = line.find_first_not_of (sep, pos2) - 1;
380 
381  c = (c > j + 1 ? c : j + 1);
382  if (r > rmax || c > cmax)
383  {
384  // Use resize_and_fill for the case of not-equal
385  // length rows.
386  rmax = 2*r;
387  cmax = c;
388  if (iscmplx)
389  cdata.resize (rmax, cmax);
390  else
391  rdata.resize (rmax, cmax);
392  }
393 
394  tmp_stream.str (str);
395  tmp_stream.clear ();
396 
397  double x = octave_read_double (tmp_stream);
398  if (tmp_stream)
399  {
400  if (tmp_stream.eof ())
401  {
402  if (iscmplx)
403  cdata(i,j++) = x;
404  else
405  rdata(i,j++) = x;
406  }
407  else if (std::toupper (tmp_stream.peek ()) == 'I')
408  {
409  // This is to allow pure imaginary numbers.
410  if (iscmplx)
411  cdata(i,j++) = x;
412  else
413  rdata(i,j++) = x;
414  }
415  else
416  {
417  double y = octave_read_double (tmp_stream);
418 
419  if (! iscmplx && y != 0.)
420  {
421  iscmplx = true;
422  cdata = ComplexMatrix (rdata);
423  }
424 
425  if (iscmplx)
426  cdata(i,j++) = Complex (x, y);
427  else
428  rdata(i,j++) = x;
429  }
430  }
431  else if (iscmplx)
432  cdata(i,j++) = empty_value;
433  else
434  rdata(i,j++) = empty_value;
435 
436  if (pos2 != std::string::npos)
437  pos1 = pos2 + 1;
438  else
439  pos1 = std::string::npos;
440 
441  }
442  while (pos1 != std::string::npos);
443 
444  if (i == r1)
445  break;
446 
447  i++;
448  }
449 
450  if (r1 >= r)
451  r1 = r - 1;
452  if (c1 >= c)
453  c1 = c - 1;
454 
455  // Now take the subset of the matrix if there are any values.
456  if (i > 0 || j > 0)
457  {
458  if (iscmplx)
459  cdata = cdata.extract (0, c0, r1, c1);
460  else
461  rdata = rdata.extract (0, c0, r1, c1);
462  }
463 
464  if (iscmplx)
465  return ovl (cdata);
466  else
467  return ovl (rdata);
468 }
469 
470 /*
471 %!shared file
472 %! file = tempname ();
473 %! fid = fopen (file, "wt");
474 %! fwrite (fid, "1, 2, 3\n4, 5, 6\n7, 8, 9\n10, 11, 12");
475 %! fclose (fid);
476 
477 %!assert (dlmread (file), [1, 2, 3; 4, 5, 6; 7, 8, 9;10, 11, 12])
478 %!assert (dlmread (file, ","), [1, 2, 3; 4, 5, 6; 7, 8, 9; 10, 11, 12])
479 %!assert (dlmread (file, ",", [1, 0, 2, 1]), [4, 5; 7, 8])
480 %!assert (dlmread (file, ",", "B1..C2"), [2, 3; 5, 6])
481 %!assert (dlmread (file, ",", "B1:C2"), [2, 3; 5, 6])
482 %!assert (dlmread (file, ",", "..C2"), [1, 2, 3; 4, 5, 6])
483 %!assert (dlmread (file, ",", 0, 1), [2, 3; 5, 6; 8, 9; 11, 12])
484 %!assert (dlmread (file, ",", "B1.."), [2, 3; 5, 6; 8, 9; 11, 12])
485 %!error (dlmread (file, ",", [0 1]))
486 
487 %!test
488 %! unlink (file);
489 
490 %!shared file
491 %! file = tempname ();
492 %! fid = fopen (file, "wt");
493 %! fwrite (fid, "1, 2, 3\n4+4i, 5, 6\n7, 8, 9\n10, 11, 12");
494 %! fclose (fid);
495 
496 %!assert (dlmread (file), [1, 2, 3; 4 + 4i, 5, 6; 7, 8, 9; 10, 11, 12])
497 %!assert (dlmread (file, ","), [1, 2, 3; 4 + 4i, 5, 6; 7, 8, 9; 10, 11, 12])
498 %!assert (dlmread (file, ",", [1, 0, 2, 1]), [4 + 4i, 5; 7, 8])
499 %!assert (dlmread (file, ",", "A2..B3"), [4 + 4i, 5; 7, 8])
500 %!assert (dlmread (file, ",", "A2:B3"), [4 + 4i, 5; 7, 8])
501 %!assert (dlmread (file, ",", "..B3"), [1, 2; 4 + 4i, 5; 7, 8])
502 %!assert (dlmread (file, ",", 1, 0), [4 + 4i, 5, 6; 7, 8, 9; 10, 11, 12])
503 %!assert (dlmread (file, ",", "A2.."), [4 + 4i, 5, 6; 7, 8, 9; 10, 11, 12])
504 %!error (dlmread (file, ",", [0 1]))
505 
506 %!test
507 %! unlink (file);
508 */
double octave_read_double(std::istream &is)
Definition: lo-utils.h:105
static bool parse_range_spec(const octave_value &range_spec, octave_idx_type &rlo, octave_idx_type &clo, octave_idx_type &rup, octave_idx_type &cup)
Definition: dlmread.cc:84
fname
Definition: load-save.cc:754
void resize(octave_idx_type nr, octave_idx_type nc, double rfv=0)
Definition: dMatrix.h:145
Matrix extract(octave_idx_type r1, octave_idx_type c1, octave_idx_type r2, octave_idx_type c2) const
Definition: dMatrix.cc:398
OCTAVE_EXPORT octave_value_list isa nd deftypefn *return ovl(args(0).is_integer_type())
OCTINTERP_API void print_usage(void)
Definition: defun.cc:52
friend class ComplexMatrix
Definition: dMatrix.h:126
#define DEFUN(name, args_name, nargout_name, doc)
Definition: defun.h:46
void error(const char *fmt,...)
Definition: error.cc:570
OCTAVE_EXPORT octave_value_list return the value of the option it must match the dimension of the state and the relative tolerance must also be a vector of the same length tem it must match the dimension of the state and the absolute tolerance must also be a vector of the same length The local error test applied at each integration step is xample roup calculate Y_a and Y _d item Given calculate Y nd enumerate In either initial values for the given components are input
Definition: DASPK-opts.cc:739
std::istream * input_stream(void)
Definition: oct-stream.h:363
static std::string tilde_expand(const std::string &)
Definition: file-ops.cc:301
JNIEnv void * args
Definition: ov-java.cc:67
octave_idx_type numel(const octave_value_list &idx)
Definition: ov.h:411
std::string string_value(bool force=false) const
Definition: ov.h:908
nd deftypefn *octave_map m
Definition: ov-struct.cc:2058
int nargin
Definition: graphics.cc:10115
bool is_string(void) const
Definition: ov.h:578
std::string str
Definition: hash.cc:118
static const octave_idx_type idx_max
Definition: dlmread.cc:44
static octave_stream lookup(int fid, const std::string &who="")
Definition: oct-stream.cc:7257
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
charNDArray max(char d, const charNDArray &m)
Definition: chNDArray.cc:228
OCTINTERP_API std::string find_data_file_in_load_path(const std::string &fcn, const std::string &file, bool require_regular_file=false)
void resize(octave_idx_type nr, octave_idx_type nc, const Complex &rfv=Complex(0))
Definition: CMatrix.h:184
subroutine stat(x, n, av, var, xmin, xmax)
Definition: tstgmn.for:111
OCTINTERP_API std::string do_string_escapes(const std::string &s)
=val(i)}if ode{val(i)}occurs in table i
Definition: lookup.cc:239
static bool read_cell_spec(std::istream &is, octave_idx_type &row, octave_idx_type &col)
Definition: dlmread.cc:48
Array< double > vector_value(bool frc_str_conv=false, bool frc_vec_conv=false) const
Definition: ov.cc:1798
the element is set to zero In other the statement xample y
Definition: data.cc:5342
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
ComplexMatrix extract(octave_idx_type r1, octave_idx_type c1, octave_idx_type r2, octave_idx_type c2) const
Definition: CMatrix.cc:686
OCTAVE_EXPORT octave_value_list or cell arrays Arguments are concatenated vertically The returned values are padded with blanks as needed to make each row of the string array have the same length Empty input strings are significant and will concatenated in the output For numerical each element is converted to the corresponding ASCII character A range error results if an input is outside the ASCII range(0-255).For cell arrays
where the brackets indicate optional arguments and and character or cell array For character arrays the conversion is repeated for every row
Definition: str2double.cc:342
F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T const F77_REAL const F77_REAL F77_REAL &F77_RET_T const F77_DBLE const F77_DBLE F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T const F77_DBLE F77_DBLE &F77_RET_T const F77_REAL F77_REAL &F77_RET_T F77_REAL F77_REAL &F77_RET_T F77_DBLE F77_DBLE &F77_RET_T const F77_DBLE * x
bool is_real_matrix(void) const
Definition: ov.h:554