1########################################################################
2##
3## Copyright (C) 1996-2021 The Octave Project Developers
4##
5## See the file COPYRIGHT.md in the top-level directory of this
6## distribution or <https://octave.org/copyright/>.
7##
8## This file is part of Octave.
9##
10## Octave is free software: you can redistribute it and/or modify it
11## under the terms of the GNU General Public License as published by
12## the Free Software Foundation, either version 3 of the License, or
13## (at your option) any later version.
14##
15## Octave is distributed in the hope that it will be useful, but
16## WITHOUT ANY WARRANTY; without even the implied warranty of
17## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18## GNU General Public License for more details.
19##
20## You should have received a copy of the GNU General Public License
21## along with Octave; see the file COPYING.  If not, see
22## <https://www.gnu.org/licenses/>.
23##
24########################################################################
25
26## -*- texinfo -*-
27## @deftypefn  {} {} index (@var{s}, @var{t})
28## @deftypefnx {} {} index (@var{s}, @var{t}, @var{direction})
29## Return the position of the first occurrence of the string @var{t} in the
30## string @var{s}, or 0 if no occurrence is found.
31##
32## @var{s} may also be a string array or cell array of strings.
33##
34## For example:
35##
36## @example
37## @group
38## index ("Teststring", "t")
39##     @result{} 4
40## @end group
41## @end example
42##
43## If @var{direction} is @qcode{"first"}, return the first element found.
44## If @var{direction} is @qcode{"last"}, return the last element found.
45##
46## @seealso{find, rindex}
47## @end deftypefn
48
49function n = index (s, t, direction = "first")
50
51  if (nargin < 2 || nargin > 3)
52    print_usage ();
53  endif
54
55  if (ischar (s))
56    if (! isrow (s))
57      s = cellstr (s);  # Handle string arrays by conversion to cellstr
58    endif
59  elseif (! iscellstr (s))
60    error ("index: S must be a string, string array, or cellstr");
61  endif
62
63  f = strfind (s, t);
64  if (isempty (f))
65    f = 0;
66  elseif (iscell (f))
67    f(cellfun ("isempty", f)) = {0};
68  endif
69
70  direction = tolower (direction);
71
72  if (strcmp (direction, "first"))
73    if (iscell (f))
74      n = cellfun ("min", f);
75    else
76      n = f(1);
77    endif
78  elseif (strcmp (direction, "last"))
79    if (iscell (f))
80      n = cellfun ("max", f);
81    else
82      n = f(end);
83    endif
84  else
85    error ('index: DIRECTION must be either "first" or "last"');
86  endif
87
88endfunction
89
90
91%!assert (index ("foobarbaz", "b"), 4)
92%!assert (index ("foobarbaz", "z"), 9)
93
94%!assert (index ("astringbstringcstring", "s"), 2)
95%!assert (index ("astringbstringcstring", "st"), 2)
96%!assert (index ("astringbstringcstring", "str"), 2)
97%!assert (index ("astringbstringcstring", "string"), 2)
98%!assert (index ("abc---", "abc+++"), 0)
99
100## test everything out in reverse
101%!assert (index ("astringbstringcstring", "s", "last"), 16)
102%!assert (index ("astringbstringcstring", "st", "last"), 16)
103%!assert (index ("astringbstringcstring", "str", "last"), 16)
104%!assert (index ("astringbstringcstring", "string", "last"), 16)
105%!assert (index ("abc---", "abc+++", "last"), 0)
106
107%!test
108%! str = char ("Hello", "World", "Goodbye", "World");
109%! assert (index (str, "o"), [5; 2; 2; 2]);
110%! assert (index (str, "o", "last"), [5; 2; 3; 2]);
111%! str = cellstr (str);
112%! assert (index (str, "o"), [5; 2; 2; 2]);
113%! assert (index (str, "o", "last"), [5; 2; 3; 2]);
114
115## Test input validation
116%!error index ()
117%!error index ("a")
118%!error index ("a", "b", "first", "d")
119%!error index (1, "bar")
120%!error index ("foo", "bar", 3)
121