1########################################################################
2##
3## Copyright (C) 2009-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  {} {[@var{cstr}] =} ostrsplit (@var{s}, @var{sep})
28## @deftypefnx {} {[@var{cstr}] =} ostrsplit (@var{s}, @var{sep}, @var{strip_empty})
29## Split the string @var{s} using one or more separators @var{sep} and return
30## a cell array of strings.
31##
32## Consecutive separators and separators at boundaries result in empty
33## strings, unless @var{strip_empty} is true.  The default value of
34## @var{strip_empty} is false.
35##
36## 2-D character arrays are split at separators and at the original column
37## boundaries.
38##
39## Example:
40##
41## @example
42## @group
43## ostrsplit ("a,b,c", ",")
44##       @result{}
45##           @{
46##             [1,1] = a
47##             [1,2] = b
48##             [1,3] = c
49##           @}
50##
51## ostrsplit (["a,b" ; "cde"], ",")
52##       @result{}
53##           @{
54##             [1,1] = a
55##             [1,2] = b
56##             [1,3] = cde
57##           @}
58## @end group
59## @end example
60## @seealso{strsplit, strtok}
61## @end deftypefn
62
63function cstr = ostrsplit (s, sep, strip_empty = false)
64
65  if (nargin < 2 || nargin > 3)
66    print_usage ();
67  elseif (! ischar (s) || ! ischar (sep))
68    error ("ostrsplit: S and SEP must be string values");
69  elseif (! isscalar (strip_empty))
70    error ("ostrsplit: STRIP_EMPTY must be a scalar value");
71  endif
72
73  if (isempty (s))
74    cstr = cell (size (s));
75  else
76    if (rows (s) > 1)
77      ## For 2-D arrays, add separator character at line boundaries
78      ## and transform to single string
79      s(:, end+1) = sep(1);
80      s = reshape (s.', 1, numel (s));
81      s(end) = [];
82    endif
83
84    ## Split s according to delimiter
85    if (isscalar (sep))
86      ## Single separator
87      idx = find (s == sep);
88    else
89      ## Multiple separators
90      idx = strchr (s, sep);
91    endif
92
93    ## Get substring lengths.
94    if (isempty (idx))
95      strlens = length (s);
96    else
97      strlens = [idx(1)-1, diff(idx)-1, numel(s)-idx(end)];
98    endif
99    ## Remove separators.
100    s(idx) = [];
101    if (strip_empty)
102      ## Omit zero lengths.
103      strlens = strlens(strlens != 0);
104    endif
105
106    ## Convert!
107    cstr = mat2cell (s, 1, strlens);
108  endif
109
110endfunction
111
112
113%!assert (ostrsplit ("road to hell", " "), {"road", "to", "hell"})
114%!assert (ostrsplit ("road to^hell", " ^"), {"road", "to", "hell"})
115%!assert (ostrsplit ("road   to--hell", " -", true), {"road", "to", "hell"})
116%!assert (ostrsplit (char ("a,bc", ",de"), ","),
117%!        {"a", "bc", char(ones(1,0)), "de "})
118%!assert (ostrsplit (char ("a,bc", ",de"), ",", true), {"a", "bc", "de "})
119%!assert (ostrsplit (char ("a,bc", ",de"), ", ", true), {"a", "bc", "de"})
120
121## Test input validation
122%!error ostrsplit ()
123%!error ostrsplit ("abc")
124%!error ostrsplit ("abc", "b", true, 4)
125%!error <S and SEP must be string values> ostrsplit (123, "b")
126%!error <S and SEP must be string values> ostrsplit ("abc", 1)
127%!error <STRIP_EMPTY must be a scalar value> ostrsplit ("abc", "def", ones (3,3))
128