changeset 28231:cbcf6c064622

startsWith.m: overhaul function. * startsWith.m: Use @group within @example blocks in documentation. Clarify docstring text. Add regexp, strncmp, strncmpi to @seealso reference. Combine input validation in to smaller code blocks. Eliminate try/catch block by using isreal() test. Declare retval to be of logical type rather than double type. Update BIST tests.
author Rik <rik@octave.org>
date Sun, 19 Apr 2020 18:34:09 -0700
parents cb0194e0cb0e
children 49384057fb03
files scripts/strings/startsWith.m
diffstat 1 files changed, 73 insertions(+), 84 deletions(-) [+]
line wrap: on
line diff
--- a/scripts/strings/startsWith.m	Sat Apr 18 17:35:25 2020 -0700
+++ b/scripts/strings/startsWith.m	Sun Apr 19 18:34:09 2020 -0700
@@ -25,94 +25,91 @@
 
 ## -*- texinfo -*-
 ## @deftypefn  {} {@var{retval} =} startsWith (@var{str}, @var{pattern})
-## @deftypefnx {} {@var{retval} =} startsWith (@var{str}, @var{pattern}, "IgnoreCase", @var{confirm_ignore})
-## Checks that a cell array of strings starts with a pattern
+## @deftypefnx {} {@var{retval} =} startsWith (@var{str}, @var{pattern}, "IgnoreCase", @var{ignore_case})
+## Check whether string(s) start with pattern(s).
 ##
-## Return an array of logical values that indicates which strings in the cell
-## array of strings --- or the string --- @var{str} starts with a string in the
-## cell array of strings --- or the string --- @var{pattern}
+## Return an array of logical values that indicates which string(s) in the
+## input @var{str} (a single string or cell array of strings) begin with
+## the input @var{pattern} (a single string or cell array of strings).
 ##
-## If the parameter @qcode{"IgnoreCase"} is set to true, then the function
-## will ignore the letter case of @var{str} and @var{pattern}.  By default, the
-## comparison is case sensitive.
+## If the value of the parameter @qcode{"IgnoreCase"} is true, then the
+## function will ignore the letter case of @var{str} and @var{pattern}.  By
+## default, the comparison is case sensitive.
 ##
 ## Examples:
 ##
 ## @example
+## @group
 ## ## one string and one pattern while considering case
 ## startsWith ("hello", "he")
 ##       @result{}  1
+## @end group
 ##
+## @group
 ## ## one string and one pattern while ignoring case
 ## startsWith ("hello", "HE", "IgnoreCase", true)
 ##       @result{}  1
+## @end group
 ##
+## @group
 ## ## multiple strings and multiple patterns while considering case
 ## startsWith (@{"lab work.pptx", "data.txt", "foundations.ppt"@},
 ##             @{"lab", "data"@})
 ##       @result{}  1  1  0
+## @end group
 ##
+## @group
 ## ## multiple strings and one pattern while considering case
 ## startsWith (@{"DATASHEET.ods", "data.txt", "foundations.ppt"@},
 ##             "data", "IgnoreCase", false)
 ##       @result{}  0  1  0
+## @end group
 ##
+## @group
 ## ## multiple strings and one pattern while ignoring case
 ## startsWith (@{"DATASHEET.ods", "data.txt", "foundations.ppt"@},
 ##             "data", "IgnoreCase", true)
 ##       @result{}  1  1  0
+## @end group
 ## @end example
 ##
-## @seealso{endsWith, strcmp, strcmpi}
+## @seealso{endsWith, regexp, strncmp, strncmpi}
 ## @end deftypefn
 
-function retval = startsWith (str, pattern, ignore_case, confirm_ignore)
-  if (! (nargin == 2 || nargin == 4))
+function retval = startsWith (str, pattern, IgnoreCase, ignore_case)
+
+  if (nargin != 2 && nargin != 4)
     print_usage ();
   endif
 
-  ## check input str and pattern
-  if (! (iscellstr (str) || ischar (str))
-      || ! (iscellstr (pattern) || ischar (pattern)))
-    error ("startsWith: arguments must be strings or cell arrays of strings");
-  else
-    str = cellstr (str);
-    pattern = cellstr (pattern);
+  ## Validate input str and pattern
+  if (! (iscellstr (str) || ischar (str)))
+    error ("startsWith: STR must be a string or cell array of strings");
+  endif
+  if (! (iscellstr (pattern) || ischar (pattern)))
+    error ("startsWith: PATTERN must be a string or cell array of strings");
   endif
 
-  retval = zeros (size (str));
+  str = cellstr (str);
+  pattern = cellstr (pattern);
 
   if (nargin == 2)
-    IgnoreFlag = false;
-  endif
-
-  if (nargin == 4)
-    ## check third input argument
-    if (! ischar (ignore_case) || isempty (ignore_case))
+    ignore_case = false;
+  else
+    ## For Matlab compatibility accept any abbreviation of 3rd argument
+    if (! ischar (IgnoreCase) || isempty (IgnoreCase)
+        || ! strncmpi (IgnoreCase, "IgnoreCase", length (IgnoreCase)))
       error ('startsWith: third input must be "IgnoreCase"');
     endif
 
-    ## to be compatible with MATLAB
-    ## (MATLAB accepts the command with "I", "i", "Ig", "IG" ..etc )
-    if (! strncmpi (ignore_case, "IgnoreCase", length (ignore_case)))
-      error (['startsWith: invalid argument "%s"; ', ...
-              'third input must be "IgnoreCase"'], ignore_case);
+    if (! isscalar (ignore_case) || ! isreal (ignore_case))
+      error ('startsWith: "IgnoreCase" value must be a logical scalar');
     endif
-
-    if (! isscalar (confirm_ignore))
-      error ("startsWith: 'IgnoreCase' value must be a logical scalar.");
-    endif
-
-    ## to be compatible with MATLAB
-    ## (MATLAB accepts the command with true, 5, 1 ..etc  )
-    try
-      IgnoreFlag = logical (confirm_ignore);
-    catch
-      error ("startsWith: 'IgnoreCase' value must be a logical scalar");
-    end_try_catch
+    ignore_case = logical (ignore_case);
   endif
 
-  if (IgnoreFlag)
+  retval = false (size (str));
+  if (ignore_case)
     for j = 1:numel (pattern)
       retval |= strncmpi (str, pattern{j}, length (pattern{j}));
     endfor
@@ -128,56 +125,48 @@
 ## Test simple use with one string and one pattern
 %!assert (startsWith ("hello", "he"))
 %!assert (! startsWith ("hello", "HE"))
-%!assert (startsWith ("hello", "HE", "i", 5)) #  check compatibility with MATLAB
+%!assert (startsWith ("hello", "HE", "i", 5))
 %!assert (! startsWith ("hello", "no"))
 
 ## Test multiple strings with a single pattern
 %!test
-%!  str = {"data science", "dataSheet.ods", "myFunc.m"; "foundations.ppt", ...
-%!         "results.txt", "myFile.odt"};
-%!  pattern = "data";
-%!  correct_ans = [true, true, false; false, false, false];
-%!  assert (startsWith (str, pattern), correct_ans)
+%! str = {"data science", "dataSheet.ods", "myFunc.m"; "foundations.ppt", ...
+%!        "results.txt", "myFile.odt"};
+%! pattern = "data";
+%! expected = [true, true, false; false, false, false];
+%! assert (startsWith (str, pattern), expected);
 
 ## Test multiple strings with multiple patterns
 %!test
-%!  str = {"lab work.pptx", "myFile.odt", "data.txt", "foundations.ppt"};
-%!  pattern = {"lab", "data"};
-%!  correct_ans = [true, false, true, false];
-%!  assert (startsWith (str, pattern), correct_ans)
+%! str = {"lab work.pptx", "myFile.odt", "data.txt", "foundations.ppt"};
+%! pattern = {"lab", "data"};
+%! expected = [true, false, true, false];
+%! assert (startsWith (str, pattern), expected);
 
 ## Test IgnoreCase
 %!test
-%!  str = {"DATASHEET.ods", "myFile.odt", "data.txt", "foundations.ppt"};
-%!  pattern = "data";
-%!  correct_ans_with_ignore = [true, false, true, false];
-%!  correct_ans_without_ignore = [false, false, true, false];
-%!  assert (startsWith (str, pattern, "IgnoreCase", true), ...
-%!          correct_ans_with_ignore)
-%!  assert (startsWith (str, pattern, "IgnoreCase", false), ...
-%!          correct_ans_without_ignore)
-%!  assert (startsWith (str, pattern, "I", 500), ...
-%!          correct_ans_with_ignore)  #  check compatibility with MATLAB
-%!  assert (startsWith (str, pattern, "iG", 0), ...
-%!          correct_ans_without_ignore) #  check compatibility with MATLAB
-
-## Test error detection
-%!error <must be strings or cell arrays of strings> startsWith (152, "hi")
+%! str = {"DATASHEET.ods", "myFile.odt", "data.txt", "foundations.ppt"};
+%! pattern = "data";
+%! expected_ignore = [true, false, true, false];
+%! expected_wo_ignore = [false, false, true, false];
+%! assert (startsWith (str, pattern, "IgnoreCase", true), expected_ignore);
+%! assert (startsWith (str, pattern, "IgnoreCase", false), expected_wo_ignore);
+%! assert (startsWith (str, pattern, "I", 500), expected_ignore);
+%! assert (startsWith (str, pattern, "iG", 0), expected_wo_ignore);
 
-%!error <must be strings or cell arrays of strings> startsWith ("hello", 152)
-
-%!error <'IgnoreCase' value must be a logical scalar> ...
-%!      startsWith ("hello", "hi", "i", "true")
-
-%!error <'IgnoreCase' value must be a logical scalar> ...
-%!      startsWith ("hello", "hi", "i", [1, 2])
-
-%!error <invalid argument "ignire"; third input must be> ...
-%!      startsWith ("hello", "he", "ignire", 1)
-
-%!error <invalid argument "IgnoreCasefd"; third input must be> ...
-%!      startsWith ("hello", "he", "IgnoreCasefd", 1)
-
+## Test input validation
+%!error startsWith ()
+%!error startsWith ("A")
+%!error startsWith ("A", "B", "C")
+%!error startsWith ("A", "B", "C", "D", "E")
+%!error <STR must be a string> startsWith (152, "hi")
+%!error <STR must be a .* cell array of strings> startsWith ({152}, "hi")
+%!error <PATTERN must be a string> startsWith ("hi", 152)
+%!error <PATTERN must be a .* cell array of strings> startsWith ("hi", {152})
+%!error <third input must be "IgnoreCase"> startsWith ("hello", "he", 1, 1)
 %!error <third input must be "IgnoreCase"> startsWith ("hello", "he", "", 1)
-
-%!error <third input must be "IgnoreCase"> startsWith ("hello", "he", {5}, 1)
+%!error <third input must be "IgnoreCase"> startsWith ("hello", "he", "foo", 1)
+%!error <"IgnoreCase" value must be a logical scalar>
+%! startsWith ("hello", "hi", "i", "true");
+%!error <"IgnoreCase" value must be a logical scalar>
+%! startsWith ("hello", "hi", "i", {true});