changeset 11141:224c80da37c5

textscan.m: Add new function.
author Ben Abbott <bpabbott@mac.com>
date Sat, 23 Oct 2010 13:37:36 +0800
parents 8aa93f43bae8
children 3450551f591e
files scripts/ChangeLog scripts/io/module.mk scripts/io/textscan.m scripts/miscellaneous/unimplemented.m
diffstat 4 files changed, 149 insertions(+), 4 deletions(-) [+]
line wrap: on
line diff
--- a/scripts/ChangeLog	Fri Oct 22 21:18:00 2010 -0400
+++ b/scripts/ChangeLog	Sat Oct 23 13:37:36 2010 +0800
@@ -1,3 +1,8 @@
+2010-10-23  Ben Abbott <bpabbott@mac.com>
+
+	* io/textscan.m, miscellaneous/unimplemented.m, io/module.mk:
+	New function.
+
 2010-10-22  Ben Abbott <bpabbott@mac.com>
 
 	* plot/legend.m: Trivial fix to allow legend handle to be returned.
--- a/scripts/io/module.mk	Fri Oct 22 21:18:00 2010 -0400
+++ b/scripts/io/module.mk	Sat Oct 23 13:37:36 2010 +0800
@@ -7,6 +7,7 @@
   io/dlmwrite.m \
   io/fileread.m \
   io/strread.m \
+  io/textscan.m \
   io/textread.m
 
 FCN_FILES += $(io_FCN_FILES)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/io/textscan.m	Sat Oct 23 13:37:36 2010 +0800
@@ -0,0 +1,143 @@
+## Copyright (C) 2010 Ben Abbott <bpabbott@mac.com>
+##
+## This file is part of Octave.
+##
+## Octave is free software; you can redistribute it and/or modify it
+## under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 3 of the License, or (at
+## your option) any later version.
+##
+## Octave is distributed in the hope that it will be useful, but
+## WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+## General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with Octave; see the file COPYING.  If not, see
+## <http://www.gnu.org/licenses/>.
+
+## -*- texinfo -*-
+## @deftypefn  {Function File} {@var{c} =} textscan (@var{fid}, @var{format})
+## @deftypefnx {Function File} {@var{c} =} textscan (@var{fid}, @var{format}, @
+## @var{n})
+## @deftypefnx {Function File} {@var{c} =} textscan (@var{fid}, @var{format}, @
+## @var{param}, @var{value}, @dots{})
+## @deftypefnx {Function File} {@var{c} =} textscan (@var{fid}, @var{format}, @
+## @var{n}, @var{param}, @var{value}, @dots{})
+## @deftypefnx {Function File} {@var{a} =} textscan (@var{str}, @dots{})
+## @deftypefnx {Function File} {[@var{a}, @var{position}] =} textscan (@dots{})
+## Read data from a text file.
+##
+## The file associated with @var{fid} is read and parsed according to @var{format}.
+## The function behaves like @code{strread} except it works by parsing a file
+## instead of a string.  See the documentation of @code{strread} for details.
+## In addition to the options supported by @code{strread}, this function
+## supports one more:
+## @itemize
+## @item "headerlines":
+## @end itemize
+## The first @var{value} number of lines of @var{str} are skipped.
+##
+## The optional input, @var{n}, specifes the number of lines to be read from
+## the file, associated with @var{fid}.
+##
+## The output, @var{c}, is a cell array whose length is given by the number
+## of format specifiers.
+##
+## The second output, @var{position}, provides the position, in characters,
+## from the beginning of the file.
+##
+## @seealso{dlmread, fscanf, load, strread, textread}
+## @end deftypefn
+
+function [c, p] = textscan (fid, formatstr, varargin)
+
+  ## Check input
+  if (nargin < 1)
+    print_usage ();
+  elseif (nargin == 1 || isempty (formatstr))
+    formatstr = "%f";
+  endif
+
+  if (nargin > 2 && isnumeric (varargin{1}))
+    nlines = varargin{1};
+    args = varargin(2:end);
+  else
+    nlines = Inf;
+    args = varargin;
+  endif
+
+  if (! any (strcmpi (args, "emptyvalue")))
+    ## Matlab returns NaNs for missing values
+    args{end+1} = "emptyvalue";
+    args{end+1} = NaN;
+  endif
+
+  if (isa (fid, "double") && fid > 0 || ischar (fid))
+    if (ischar (formatstr))
+      if (ischar (fid))
+        if (nargout == 2)
+          error ("textscan: cannot provide postion information for character input")
+        endif
+        str = fid;
+      else
+        ## Maybe skip header lines
+        headerlines = find (strcmpi (args, "headerlines"), 1);
+        if (! isempty (headerlines))
+          fskipl (fid, headerlines);
+          args(headerlines:headerlines+1) = [];
+        endif
+        if (isfinite (nlines))
+          str = "";
+          for n = 1:nlines
+            str = strcat (str, fgets (fid));
+          endfor
+            else
+          str = fread (fid, "char=>char").';
+        endif
+      endif
+
+      ## Determine the number of data fields
+      num_fields = numel (strfind (formatstr, "%")) - ...
+                   numel (idx_star = strfind (formatstr, "%*"));
+
+      ## Call strread to make it do the real work
+      c = cell (1, num_fields);
+      [c{:}] = strread (str, formatstr, args{:});
+
+      if (ischar (fid) && isfinite (nlines))
+        c = cellfun (@(x) x(1:nlines), c, "UniformOutput", false);
+      endif
+
+      if (nargout == 2)
+        p = ftell (fid);
+      endif
+
+    else
+      error ("textscan: second input must be a format specification");
+    endif
+  else
+    error ("textscan: expecting first argument to be a file id or character string");
+  endif
+
+endfunction
+
+%!test
+%! str = "1,  2,  3,  4\n 5,  ,  ,  8\n 9, 10, 11, 12";
+%! fmtstr = "%f %d %f %s";
+%! c = textscan (str, fmtstr, 2, "delimiter", ",", "emptyvalue", -Inf);
+%! assert (isequal (c{1}, [1;5]))
+%! assert (length (c{1}), 2);
+%! assert (iscellstr (c{4}))
+%! assert (isequal (c{3}, [3; -Inf]))
+
+%!test
+%! b = [10:10:100];
+%! b = [b; 8*b/5];
+%! str = sprintf ("%g miles/hr = %g kilometers/hr\n", b);
+%! fmt = "%f miles/hr = %f kilometers/hr";
+%! c = textscan (str, fmt);
+%! assert (b(1,:)', c{1})
+%! assert (b(2,:)', c{2})
+
+
--- a/scripts/miscellaneous/unimplemented.m	Fri Oct 22 21:18:00 2010 -0400
+++ b/scripts/miscellaneous/unimplemented.m	Sat Oct 23 13:37:36 2010 +0800
@@ -45,9 +45,6 @@
     "Matlab-compatible ODE functions are provided by the odepkg package.  ",...
     "See @url{http://octave.sf.net/odepkg/}."];
   
-  case "textscan"
-    txt = ["textscan is not implemented.  Consider using textread or sscanf."];
-
   otherwise
     if (ismember (fcn, missing_functions ()))
 
@@ -378,7 +375,6 @@
   "syntax", 
   "tetramesh", 
   "texlabel", 
-  "textscan", 
   "textwrap", 
   "tfqmr", 
   "timer",