changeset 28746:7dcc4cb6da53

Expand sttrrep to work an character matrices (bug #57867) * strfind.cc: Clarify error message (there is only *one* optional argument). Place error() calls early in input validation. Detect single row char matrix, a.k.a, a string and call existing code qs_replace. Detect multi-row char matrix and add new code to loop over rows calling qs_replace for each row and building up results in a return charMatrix. Rename variables in code pathway where input is a Cell for clarity. Use iscellstr() to simplify for loop by removing test for is_string in every iteration. Add BIST test for new multi-row behavior. Add expected output for %!error BIST tests.
author Rik <rik@octave.org>
date Mon, 14 Sep 2020 16:32:42 -0700
parents ffdb29f7baab
children 9cd608134ec5
files libinterp/corefcn/strfind.cc
diffstat 1 files changed, 50 insertions(+), 18 deletions(-) [+]
line wrap: on
line diff
--- a/libinterp/corefcn/strfind.cc	Mon Sep 14 14:38:42 2020 -0700
+++ b/libinterp/corefcn/strfind.cc	Mon Sep 14 16:32:42 2020 -0700
@@ -418,17 +418,18 @@
   if (nargin == 5)
     {
       if (! args(3).is_string () || ! args(4).is_scalar_type ())
-        error ("strrep: invalid optional arguments");
+        error ("strrep: invalid optional argument");
 
       std::string opt = args(3).string_value ();
-      if (opt == "overlaps")
-        overlaps = args(4).bool_value ();
-      else
+      if (opt != "overlaps")
         error ("strrep: unknown option: %s", opt.c_str ());
+
+      overlaps = args(4).bool_value ();
     }
 
   octave_value retval;
 
+  // Aliasing for better code readability
   octave_value argstr = args(0);
   octave_value argpat = args(1);
   octave_value argrep = args(2);
@@ -442,25 +443,42 @@
       qs_preprocess (pat, table);
 
       if (argstr.is_string ())
-        retval = qs_replace (argstr.char_array_value (), pat, rep,
-                             table, overlaps);
+        if (argstr.rows () == 1)  // most common case of a single string
+          retval = qs_replace (argstr.char_array_value (), pat, rep,
+                               table, overlaps);
+        else
+          {
+            const charMatrix argchm = argstr.char_matrix_value ();
+            octave_idx_type nel = argchm.rows ();
+            octave_idx_type nc = argchm.columns ();
+            charMatrix retchm (nel, 0);
+
+            for (octave_idx_type i = 0; i < nel; i++)
+              {
+                charMatrix rowchm;
+                rowchm = qs_replace (argchm.extract (i, 0, i, nc-1),
+                                     pat, rep, table, overlaps);
+                retchm.insert (rowchm, i, 0);
+              }
+
+            retval = retchm;
+          }
       else if (argstr.iscell ())
         {
-          const Cell argsc = argstr.cell_value ();
-          Cell retc (argsc.dims ());
-          octave_idx_type ns = argsc.numel ();
+          const Cell argcell = argstr.cell_value ();
+          if (! argcell.iscellstr ())
+            error ("strrep: each element of S must be a string");
 
-          for (octave_idx_type i = 0; i < ns; i++)
+          Cell retcell (argcell.dims ());
+          octave_idx_type nel = argcell.numel ();
+
+          for (octave_idx_type i = 0; i < nel; i++)
             {
-              octave_value argse = argsc(i);
-              if (argse.is_string ())
-                retc(i) = qs_replace (argse.char_array_value (), pat, rep,
-                                      table, overlaps);
-              else
-                error ("strrep: each element of S must be a string");
+              retcell(i) = qs_replace (argcell(i).char_array_value (),
+                                       pat, rep, table, overlaps);
             }
 
-          retval = retc;
+          retval = retcell;
         }
       else
         error ("strrep: S must be a string or cell array of strings");
@@ -478,9 +496,23 @@
 %!                "Th&%$ &%$ a test string")
 %!assert (strrep ("abababc", "abab", "xyz"), "xyzxyzc")
 %!assert (strrep ("abababc", "abab", "xyz", "overlaps", false), "xyzabc")
+%!assert (strrep ({"Hello World"; "Goodbye World"}, "World", "Jane"),
+%!                {"Hello Jane"; "Goodbye Jane"})
+%!assert (strrep (char ("Hello World", "Goodbye World"), "World", "Jane"),
+%!                char ("Hello Jane", "Goodbye Jane"))
 
 %!assert (size (strrep ("a", "a", "")), [0 0])
 
 %!error strrep ()
-%!error strrep ("foo", "bar", 3, 4)
+%!error strrep ("A")
+%!error strrep ("A", "B")
+%!error strrep ("A", "B", "C", "D")
+%!error strrep ("A", "B", "C", "D", "E", "F")
+%!error <invalid optional argument> strrep ("A", "B", "C", 3, true)
+%!error <invalid optional argument> strrep ("A", "B", "C", "str", ones (2,2))
+%!error <unknown option: foobar> strrep ("A", "B", "C", "foobar", true)
+%!error <each element of S must be a string> strrep ({"A", 1.0}, "B", "C")
+%!error <S must be a string or cell array of strings> strrep (1.0, "B", "C")
+%!error <PTN and REP arguments must be strings> strrep ("A", 1.0, "C")
+%!error <PTN and REP arguments must be strings> strrep ("A", "B", 1.0)
 */