GNU Octave 11.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 
Loading...
Searching...
No Matches
strfns.cc
Go to the documentation of this file.
1////////////////////////////////////////////////////////////////////////
2//
3// Copyright (C) 1994-2026 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#if defined (HAVE_CONFIG_H)
27# include "config.h"
28#endif
29
30#include <cctype>
31
32#include <queue>
33#include <sstream>
34
35#include "dMatrix.h"
37#include "uniconv-wrappers.h"
38#include "unistr-wrappers.h"
39
40#include "Cell.h"
41#include "defun.h"
42#include "error.h"
43#include "errwarn.h"
44#include "ov.h"
45#include "ovl.h"
46#include "unwind-prot.h"
47#include "utils.h"
48
49#include "oct-string.h"
50
52
53DEFUN (char, args, ,
54 doc: /* -*- texinfo -*-
55@deftypefn {} {@var{C} =} char (@var{A})
56@deftypefnx {} {@var{C} =} char (@var{A}, @dots{})
57@deftypefnx {} {@var{C} =} char (@var{str1}, @var{str2}, @dots{})
58@deftypefnx {} {@var{C} =} char (@var{cell_array})
59@deftypefnx {} {'' =} char ()
60
61Create a string array from one or more numeric matrices, character
62matrices, or cell arrays.
63
64Arguments are concatenated vertically. The returned values are padded with
65blanks as needed to make each row of the string array have the same length.
66Empty input strings are significant and will concatenated in the output.
67
68For numerical input, each element is converted to the corresponding ASCII
69character. A range error results if an input is outside the ASCII range
70(0-255).
71
72For cell arrays, each element is concatenated separately. Cell arrays
73converted through @code{char} can mostly be converted back with
74@code{cellstr}. For example:
75
76@example
77@group
78char ([97, 98, 99], "", @{"98", "99", 100@}, "str1", ["ha", "lf"])
79 @xresult{} ["abc "
80 " "
81 "98 "
82 "99 "
83 "d "
84 "str1"
85 "half"]
86@end group
87@end example
88@seealso{strvcat, cellstr}
89@end deftypefn */)
90{
91 octave_value retval;
92
93 int nargin = args.length ();
94
95 if (nargin == 0)
96 retval = ""; // required for Matlab compatibility
97 else if (nargin == 1)
98 retval = args(0).convert_to_str (true, true,
99 args(0).is_dq_string () ? '"' : '\'');
100 else
101 {
102 int n_elts = 0;
103
104 int max_len = 0;
105
106 std::queue<string_vector> args_as_strings;
107
108 for (int i = 0; i < nargin; i++)
109 {
110 string_vector s = args(i).xstring_vector_value ("char: unable to convert some args to strings");
111
112 if (s.numel () > 0)
113 n_elts += s.numel ();
114 else
115 n_elts += 1;
116
117 int s_max_len = s.max_length ();
118
119 if (s_max_len > max_len)
120 max_len = s_max_len;
121
122 args_as_strings.push (s);
123 }
124
125 string_vector result (n_elts);
126
127 int k = 0;
128
129 for (int i = 0; i < nargin; i++)
130 {
131 string_vector s = args_as_strings.front ();
132 args_as_strings.pop ();
133
134 int n = s.numel ();
135
136 if (n > 0)
137 {
138 for (int j = 0; j < n; j++)
139 {
140 std::string t = s[j];
141 int t_len = t.length ();
142
143 if (max_len > t_len)
144 t += std::string (max_len - t_len, ' ');
145
146 result[k++] = t;
147 }
148 }
149 else
150 result[k++] = std::string (max_len, ' ');
151 }
152
153 retval = octave_value (result, '\'');
154 }
155
156 return retval;
157}
158
159/*
160%!assert (char (), '')
161%!assert (char (100), "d")
162%!assert (char (100,100), ["d";"d"])
163%!assert (char ({100,100}), ["d";"d"])
164%!assert (char ([100,100]), ["dd"])
165%!assert (char ({100,{100}}), ["d";"d"])
166%!assert (char (100, [], 100), ["d";" ";"d"])
167%!assert (char ({100, [], 100}), ["d";" ";"d"])
168%!assert (char ({100,{100, {""}}}), ["d";"d";" "])
169%!assert (char (["a ";"be"], {"c", 100}), ["a ";"be";"c ";"d "])
170%!assert (char ("a", "bb", "ccc"), ["a "; "bb "; "ccc"])
171%!assert (char ([65, 83, 67, 73, 73]), "ASCII")
172
173%!test
174%! x = char ("foo", "bar", "foobar");
175%! assert (x(1,:), "foo ");
176%! assert (x(2,:), "bar ");
177%! assert (x(3,:), "foobar");
178*/
179
180DEFUN (strvcat, args, ,
181 doc: /* -*- texinfo -*-
182@deftypefn {} {@var{C} =} strvcat (@var{A})
183@deftypefnx {} {@var{C} =} strvcat (@var{A}, @dots{})
184@deftypefnx {} {@var{C} =} strvcat (@var{str1}, @var{str2}, @dots{})
185@deftypefnx {} {@var{C} =} strvcat (@var{cell_array})
186Create a character array from one or more numeric matrices, character
187matrices, or cell arrays.
188
189Arguments are concatenated vertically. The returned values are padded with
190blanks as needed to make each row of the string array have the same length.
191Unlike @code{char}, empty strings are removed and will not appear in the
192output.
193
194For numerical input, each element is converted to the corresponding ASCII
195character. A range error results if an input is outside the ASCII range
196(0-255).
197
198For cell arrays, each element is concatenated separately. Cell arrays
199converted through @code{strvcat} can mostly be converted back with
200@code{cellstr}. For example:
201
202@example
203@group
204strvcat ([97, 98, 99], "", @{"98", "99", 100@}, "str1", ["ha", "lf"])
205 @xresult{} ["abc "
206 "98 "
207 "99 "
208 "d "
209 "str1"
210 "half"]
211@end group
212@end example
213@seealso{char, strcat, cstrcat}
214@end deftypefn */)
215{
216 int nargin = args.length ();
217 int n_elts = 0;
218 std::size_t max_len = 0;
219 std::queue<string_vector> args_as_strings;
220
221 for (int i = 0; i < nargin; i++)
222 {
223 string_vector s = args(i).xstring_vector_value ("strvcat: unable to convert some args to strings");
224
225 std::size_t n = s.numel ();
226
227 // do not count empty strings in calculation of number of elements
228 if (n > 0)
229 {
230 for (std::size_t j = 0; j < n; j++)
231 {
232 if (! s[j].empty ())
233 n_elts++;
234 }
235 }
236
237 std::size_t s_max_len = s.max_length ();
238
239 if (s_max_len > max_len)
240 max_len = s_max_len;
241
242 args_as_strings.push (s);
243 }
244
245 string_vector result (n_elts);
246
247 octave_idx_type k = 0;
248
249 for (int i = 0; i < nargin; i++)
250 {
251 string_vector s = args_as_strings.front ();
252 args_as_strings.pop ();
253
254 std::size_t n = s.numel ();
255
256 if (n > 0)
257 {
258 for (std::size_t j = 0; j < n; j++)
259 {
260 std::string t = s[j];
261 if (t.length () > 0)
262 {
263 std::size_t t_len = t.length ();
264
265 if (max_len > t_len)
266 t += std::string (max_len - t_len, ' ');
267
268 result[k++] = t;
269 }
270 }
271 }
272 }
273
274 // Cannot use ovl. Relies on overloaded octave_value call.
275 return octave_value (result, '\'');
276}
277
278/*
279%!assert (strvcat (""), "")
280%!assert (strvcat (100) == "d")
281%!assert (strvcat (100,100), ["d";"d"])
282%!assert (strvcat ({100,100}), ["d";"d"])
283%!assert (strvcat ([100,100]), ["dd"])
284%!assert (strvcat ({100,{100}}), ["d";"d"])
285%!assert (strvcat (100, [], 100), ["d";"d"])
286%!assert (strvcat ({100, [], 100}), ["d";"d"])
287%!assert (strvcat ({100,{100, {""}}}), ["d";"d"])
288%!assert (strvcat (["a ";"be"], {"c", 100}), ["a ";"be";"c ";"d "])
289%!assert (strvcat ("a", "bb", "ccc"), ["a "; "bb "; "ccc"])
290%!assert (strvcat (), "")
291*/
292
293DEFUN (ischar, args, ,
294 doc: /* -*- texinfo -*-
295@deftypefn {} {@var{tf} =} ischar (@var{x})
296Return true if @var{x} is a character array.
297@seealso{isfloat, isinteger, islogical, isnumeric, isstring, iscellstr, isa}
298@end deftypefn */)
299{
300 if (args.length () != 1)
301 print_usage ();
302
303 return ovl (args(0).is_string ());
304}
305
306/*
307%!assert (ischar ("a"), true)
308%!assert (ischar (["ab";"cd"]), true)
309%!assert (ischar ({"ab"}), false)
310%!assert (ischar (1), false)
311%!assert (ischar ([1, 2]), false)
312%!assert (ischar ([]), false)
313%!assert (ischar ([1, 2; 3, 4]), false)
314%!assert (ischar (""), true)
315%!assert (ischar ("test"), true)
316%!assert (ischar (["test"; "ing"]), true)
317%!assert (ischar (struct ("foo", "bar")), false)
318
319%!error ischar ()
320%!error ischar ("test", 1)
321*/
322
323static octave_value
324do_strcmp_fcn (const octave_value& arg0, const octave_value& arg1,
325 octave_idx_type n, const char *fcn_name,
326 bool (*array_op) (const Array<char>&, const Array<char>&,
328 bool (*str_op) (const std::string&, const std::string&,
329 std::string::size_type))
330
331{
332 octave_value retval;
333
334 bool s1_string = arg0.is_string ();
335 bool s1_cell = arg0.iscell ();
336 bool s2_string = arg1.is_string ();
337 bool s2_cell = arg1.iscell ();
338
339 if (s1_string && s2_string)
340 retval = array_op (arg0.char_array_value (), arg1.char_array_value (), n);
341 else if ((s1_string && s2_cell) || (s1_cell && s2_string))
342 {
343 octave_value str_val, cell_val;
344
345 if (s1_string)
346 {
347 str_val = arg0;
348 cell_val = arg1;
349 }
350 else
351 {
352 str_val = arg1;
353 cell_val = arg0;
354 }
355
356 const Cell cell = cell_val.cell_value ();
357 const string_vector str = str_val.string_vector_value ();
358 octave_idx_type r = str.numel ();
359
360 if (r == 0 || r == 1)
361 {
362 // Broadcast the string.
363
364 boolNDArray output (cell_val.dims (), false);
365
366 std::string s = (r == 0 ? "" : str[0]);
367
368 if (cell_val.iscellstr ())
369 {
370 const Array<std::string> cellstr = cell_val.cellstr_value ();
371 for (octave_idx_type i = 0; i < cellstr.numel (); i++)
372 output(i) = str_op (cellstr(i), s, n);
373 }
374 else
375 {
376 // FIXME: should we warn here?
377 for (octave_idx_type i = 0; i < cell.numel (); i++)
378 {
379 if (cell(i).is_string ())
380 output(i) = str_op (cell(i).string_value (), s, n);
381 }
382 }
383
384 retval = output;
385 }
386 else if (r > 1)
387 {
388 if (cell.numel () == 1)
389 {
390 // Broadcast the cell.
391
392 const dim_vector dv (r, 1);
393 boolNDArray output (dv, false);
394
395 if (cell(0).is_string ())
396 {
397 const std::string str2 = cell(0).string_value ();
398
399 for (octave_idx_type i = 0; i < r; i++)
400 output(i) = str_op (str[i], str2, n);
401 }
402
403 retval = output;
404 }
405 else
406 {
407 // Must match in all dimensions.
408
409 boolNDArray output (cell.dims (), false);
410
411 if (cell.numel () == r)
412 {
413 if (cell_val.iscellstr ())
414 {
415 const Array<std::string> cellstr
416 = cell_val.cellstr_value ();
417 for (octave_idx_type i = 0; i < cellstr.numel (); i++)
418 output(i) = str_op (str[i], cellstr(i), n);
419 }
420 else
421 {
422 // FIXME: should we warn here?
423 for (octave_idx_type i = 0; i < r; i++)
424 {
425 if (cell(i).is_string ())
426 output(i) = str_op (str[i],
427 cell(i).string_value (), n);
428 }
429 }
430
431 retval = output;
432 }
433 else
434 retval = false;
435 }
436 }
437 }
438 else if (s1_cell && s2_cell)
439 {
440 octave_value cell1_val, cell2_val;
441 octave_idx_type r1 = arg0.numel (), r2;
442
443 if (r1 == 1)
444 {
445 // Make the singleton cell2.
446
447 cell1_val = arg1;
448 cell2_val = arg0;
449 }
450 else
451 {
452 cell1_val = arg0;
453 cell2_val = arg1;
454 }
455
456 const Cell cell1 = cell1_val.cell_value ();
457 const Cell cell2 = cell2_val.cell_value ();
458 r1 = cell1.numel ();
459 r2 = cell2.numel ();
460
461 const dim_vector size1 = cell1.dims ();
462 const dim_vector size2 = cell2.dims ();
463
464 boolNDArray output (size1, false);
465
466 if (r2 == 1)
467 {
468 // Broadcast cell2.
469
470 if (cell2(0).is_string ())
471 {
472 const std::string str2 = cell2(0).string_value ();
473
474 if (cell1_val.iscellstr ())
475 {
476 const Array<std::string> cellstr = cell1_val.cellstr_value ();
477 for (octave_idx_type i = 0; i < cellstr.numel (); i++)
478 output(i) = str_op (cellstr(i), str2, n);
479 }
480 else
481 {
482 // FIXME: should we warn here?
483 for (octave_idx_type i = 0; i < r1; i++)
484 {
485 if (cell1(i).is_string ())
486 {
487 const std::string str1 = cell1(i).string_value ();
488 output(i) = str_op (str1, str2, n);
489 }
490 }
491 }
492 }
493 }
494 else
495 {
496 if (size1 != size2)
497 error ("%s: nonconformant cell arrays", fcn_name);
498
499 if (cell1.iscellstr () && cell2.iscellstr ())
500 {
501 const Array<std::string> cellstr1 = cell1_val.cellstr_value ();
502 const Array<std::string> cellstr2 = cell2_val.cellstr_value ();
503 for (octave_idx_type i = 0; i < r1; i++)
504 output (i) = str_op (cellstr1(i), cellstr2(i), n);
505 }
506 else
507 {
508 // FIXME: should we warn here?
509 for (octave_idx_type i = 0; i < r1; i++)
510 {
511 if (cell1(i).is_string () && cell2(i).is_string ())
512 {
513 const std::string str1 = cell1(i).string_value ();
514 const std::string str2 = cell2(i).string_value ();
515 output(i) = str_op (str1, str2, n);
516 }
517 }
518 }
519 }
520
521 retval = output;
522 }
523 else
524 retval = false;
525
526 return retval;
527}
528
529
530// These are required so that they match the same signature as strncmp
531// and strncmpi and can therefore be used in do_strcmp_fcn.
532
533template <typename T, typename T_size_type>
534static bool
535strcmp_ignore_n (const T& s1, const T& s2, T_size_type)
536{ return string::strcmp (s1, s2); }
537
538template <typename T, typename T_size_type>
539static bool
540strcmpi_ignore_n (const T& s1, const T& s2, T_size_type)
541{ return string::strcmpi (s1, s2); }
542
543
544DEFUN (strcmp, args, ,
545 doc: /* -*- texinfo -*-
546@deftypefn {} {@var{tf} =} strcmp (@var{str1}, @var{str2})
547Return 1 if the character strings @var{str1} and @var{str2} are the same,
548and 0 otherwise.
549
550If either @var{str1} or @var{str2} is a cell array of strings, then an array
551of the same size is returned, containing the values described above for
552every member of the cell array. The other argument may also be a cell
553array of strings (of the same size or with only one element), char matrix
554or character string.
555
556@strong{Caution:} For compatibility with @sc{matlab}, Octave's strcmp
557function returns 1 if the character strings are equal, and 0 otherwise.
558This is just the opposite of the corresponding C library function.
559@seealso{strcmpi, strncmp, strncmpi}
560@end deftypefn */)
561{
562 if (args.length () != 2)
563 print_usage ();
564
565 return ovl (do_strcmp_fcn (args(0), args(1), 0, "strcmp",
566 strcmp_ignore_n, strcmp_ignore_n));
567}
568
569/*
570%!shared x
571%! x = char (zeros (0, 2));
572%!assert (strcmp ("", x), false)
573%!assert (strcmp (x, ""), false)
574%!assert (strcmp (x, x), true)
575## %!assert (strcmp ({""}, x), true)
576## %!assert (strcmp ({x}, ""), false)
577## %!assert (strcmp ({x}, x), true)
578## %!assert (strcmp ("", {x}), false)
579## %!assert (strcmp (x, {""}), false)
580## %!assert (strcmp (x, {x}), true)
581## %!assert (strcmp ({x; x}, ""), [false; false])
582## %!assert (strcmp ({x; x}, {""}), [false; false])
583## %!assert (strcmp ("", {x; x}), [false; false])
584## %!assert (strcmp ({""}, {x; x}), [false; false])
585%!assert (strcmp ({"foo"}, x), false)
586%!assert (strcmp ({"foo"}, "foo"), true)
587%!assert (strcmp ({"foo"}, x), false)
588%!assert (strcmp (x, {"foo"}), false)
589%!assert (strcmp ("foo", {"foo"}), true)
590%!assert (strcmp (x, {"foo"}), false)
591%!shared y
592%! y = char (zeros (2, 0));
593%!assert (strcmp ("", y), false)
594%!assert (strcmp (y, ""), false)
595%!assert (strcmp (y, y), true)
596%!assert (strcmp ({""}, y), [true; true])
597%!assert (strcmp ({y}, ""), true)
598%!assert (strcmp ({y}, y), [true; true])
599%!assert (strcmp ("", {y}), true)
600%!assert (strcmp (y, {""}), [true; true])
601%!assert (strcmp (y, {y}), [true; true])
602%!assert (strcmp ({y; y}, ""), [true; true])
603%!assert (strcmp ({y; y}, {""}), [true; true])
604%!assert (strcmp ("", {y; y}), [true; true])
605%!assert (strcmp ({""}, {y; y}), [true; true])
606%!assert (strcmp ({"foo"}, y), [false; false])
607%!assert (strcmp ({"foo"}, y), [false; false])
608%!assert (strcmp (y, {"foo"}), [false; false])
609%!assert (strcmp (y, {"foo"}), [false; false])
610%!assert (strcmp ("foobar", "foobar"), true)
611%!assert (strcmp ("foobar", "fooBar"), false)
612%!assert (strcmp ("fooba", "foobar"), false)
613
614%!error strcmp ()
615%!error strcmp ("foo", "bar", 3)
616*/
617
618DEFUN (strncmp, args, ,
619 doc: /* -*- texinfo -*-
620@deftypefn {} {@var{tf} =} strncmp (@var{str1}, @var{str2}, @var{n})
621Return 1 if the first @var{n} characters of strings @var{str1} and @var{str2}
622are the same, and 0 otherwise.
623
624@example
625@group
626strncmp ("abce", "abcd", 3)
627 @xresult{} 1
628@end group
629@end example
630
631If either @var{str1} or @var{str2} is a cell array of strings, then an array
632of the same size is returned, containing the values described above for
633every member of the cell array. The other argument may also be a cell
634array of strings (of the same size or with only one element), char matrix
635or character string.
636
637@example
638@group
639strncmp ("abce", @{"abcd", "bca", "abc"@}, 3)
640 @xresult{} [1, 0, 1]
641@end group
642@end example
643
644@strong{Caution:} For compatibility with @sc{matlab}, Octave's strncmp
645function returns true if the character strings are equal, and false
646otherwise. This is just the opposite of the corresponding C library
647function. In addition Octave's strncmp function returns true if N = 0.
648
649@sc{matlab} incompatibility : Octave's strncmp function produces an error if
650N < 0, while @sc{matlab} treats N < 0 the same as N = 0, always returning
651true.
652
653@seealso{strncmpi, strcmp, strcmpi}
654@end deftypefn */)
655{
656 if (args.length () != 3)
657 print_usage ();
658
659 octave_idx_type n = args(2).idx_type_value ();
660
661 if (n >= 0)
662 return ovl (do_strcmp_fcn (args(0), args(1), n, "strncmp",
663 string::strncmp,
664 string::strncmp));
665 else
666 error ("strncmp: N must be greater than or equal to 0");
667}
668
669/*
670%!assert (strncmp ("abce", "abc", 3), true)
671%!assert (strncmp ("abce", "aBc", 3), false)
672%!assert (strncmp (100, 100, 1), false)
673%!assert (strncmp ("abce", {"abcd", "bca", "abc"}, 3), logical ([1, 0, 1]))
674%!assert (strncmp ("abc", {"abcd", "bca", "abc"}, 4), logical ([0, 0, 1]))
675%!assert (strncmp ({"abcd", "bca", "abc"},"abce", 3), logical ([1, 0, 1]))
676%!assert (strncmp ({"abcd", "bca", "abc"},{"abcd", "bca", "abe"}, 3),
677%! logical ([1, 1, 0]))
678%!assert (strncmp ("abc", {"abcd", 10}, 2), logical ([1, 0]))
679
680%!assert <*54373> (strncmp ("abc", "abc", 100))
681%!assert <*57879> (strncmp ("abc", "abc", 0))
682%!assert <*57879> (strncmp ("abc", "def", 0))
683%!assert <*57879> (strncmp ("abc", "ac", 0))
684
685%!error strncmp ()
686%!error strncmp ("abc", "def")
687%!error <N must be greater than or equal> strncmp ("abc", "abc", -1)
688*/
689
690DEFUNX ("strcmpi", Fstrcmpi, args, ,
691 doc: /* -*- texinfo -*-
692@deftypefn {} {@var{tf} =} strcmpi (@var{str1}, @var{str2})
693Return 1 if the character strings @var{str1} and @var{str2} are the same,
694disregarding case of alphabetic characters, and 0 otherwise.
695
696If either @var{str1} or @var{str2} is a cell array of strings, then an array
697of the same size is returned, containing the values described above for
698every member of the cell array. The other argument may also be a cell
699array of strings (of the same size or with only one element), char matrix
700or character string.
701
702@strong{Caution:} For compatibility with @sc{matlab}, Octave's strcmpi
703function returns 1 if the character strings are equal, and 0 otherwise.
704This is just the opposite of the corresponding C library function.
705
706@strong{Caution:} National alphabets are not supported.
707@seealso{strcmp, strncmp, strncmpi}
708@end deftypefn */)
709{
710 if (args.length () != 2)
711 print_usage ();
712
713 return ovl (do_strcmp_fcn (args(0), args(1), 0, "strcmpi",
714 strcmpi_ignore_n, strcmpi_ignore_n));
715}
716
717/*
718%!assert (strcmpi ("abc123", "ABC123"), true)
719*/
720
721DEFUNX ("strncmpi", Fstrncmpi, args, ,
722 doc: /* -*- texinfo -*-
723@deftypefn {} {@var{tf} =} strncmpi (@var{str1}, @var{str2}, @var{n})
724Return 1 if the first @var{n} character of @var{s1} and @var{s2} are the
725same, disregarding case of alphabetic characters, and 0 otherwise.
726
727If either @var{str1} or @var{str2} is a cell array of strings, then an array
728of the same size is returned, containing the values described above for
729every member of the cell array. The other argument may also be a cell
730array of strings (of the same size or with only one element), char matrix
731or character string.
732
733@strong{Caution:} For compatibility with @sc{matlab}, Octave's strncmpi
734function returns true if the character strings are equal, and false
735otherwise. This is just the opposite of the corresponding C library
736function. In addition Octave's strncmpi function returns true if N = 0.
737
738@sc{matlab} incompatibility : Octave's strncmpi function produces an error if
739N < 0, while @sc{matlab} treats N < 0 the same as N = 0, always returning
740true.
741
742@strong{Caution:} National alphabets are not supported.
743@seealso{strncmp, strcmp, strcmpi}
744@end deftypefn */)
745{
746 if (args.length () != 3)
747 print_usage ();
748
749 octave_idx_type n = args(2).idx_type_value ();
750
751 if (n >= 0)
752 return ovl (do_strcmp_fcn (args(0), args(1), n, "strncmpi",
753 string::strncmpi,
754 string::strncmpi));
755 else
756 error ("strncmpi: N must be greater than or equal to 0");
757}
758
759/*
760%!assert (strncmpi ("abc123", "ABC456", 3))
761%!assert <*57879> (strncmpi ("abc", "abc", 0))
762%!assert <*57879> (strncmpi ("abc", "def", 0))
763%!assert <*57879> (strncmpi ("abc", "ac", 0))
764%!error <N must be greater than or equal> strncmpi ("abc", "abc", -1)
765*/
766
767DEFUN (str2double, args, ,
768 doc: /* -*- texinfo -*-
769@deftypefn {} {@var{d} =} str2double (@var{str})
770Convert a string to a real or complex number.
771
772The string must be in one of the following formats where a and b are real
773numbers and the complex unit is @qcode{'i'} or @qcode{'j'}:
774
775@itemize
776@item a + bi
777
778@item a + b*i
779
780@item a + i*b
781
782@item bi + a
783
784@item b*i + a
785
786@item i*b + a
787@end itemize
788
789If present, a and/or b are of the form @nospell{[+-]d[,.]d[[eE][+-]d]} where
790the brackets indicate optional arguments and @qcode{'d'} indicates zero or
791more digits. The special input values @code{Inf}, @code{NaN}, and @code{NA}
792are also accepted.
793
794@var{str} may be a character string, character matrix, or cell array. For
795character arrays the conversion is repeated for every row, and a double or
796complex array is returned. Empty rows in @var{s} are deleted and not
797returned in the numeric array. For cell arrays each character string
798element is processed and a double or complex array of the same dimensions as
799@var{str} is returned.
800
801For unconvertible scalar or character string input @code{str2double} returns
802a NaN@. Similarly, for character array input @code{str2double} returns a
803NaN for any row of @var{s} that could not be converted. For a cell array,
804@code{str2double} returns a NaN for any element of @var{s} for which
805conversion fails. Note that numeric elements in a mixed string/numeric
806cell array are not strings and the conversion will fail for these elements
807and return NaN.
808
809Programming Note: @code{str2double} can replace @code{str2num}, is more
810efficient, and avoids the security risk of using @code{eval} on unknown data.
811@seealso{str2num}
812@end deftypefn */)
813{
814 if (args.length () != 1)
815 print_usage ();
816
817 octave_value retval;
818
819 if (args(0).is_string ())
820 {
821 if (args(0).rows () == 0 || args(0).columns () == 0)
822 retval = Matrix (1, 1, numeric_limits<double>::NaN ());
823 else if (args(0).rows () == 1 && args(0).ndims () == 2)
824 retval = string::str2double (args(0).string_value ());
825 else
826 {
827 const string_vector sv = args(0).string_vector_value ();
828
829 retval = sv.map<Complex> (string::str2double);
830 }
831 }
832 else if (args(0).iscell ())
833 {
834 const Cell cell = args(0).cell_value ();
835
836 ComplexNDArray output (cell.dims (), numeric_limits<double>::NaN ());
837
838 for (octave_idx_type i = 0; i < cell.numel (); i++)
839 {
840 if (cell(i).is_string ())
841 output(i) = string::str2double (cell(i).string_value ());
842 }
843 retval = output;
844 }
845 else
846 retval = Matrix (1, 1, numeric_limits<double>::NaN ());
847
848 return retval;
849}
850
851/*
852%!assert (str2double ("1"), 1)
853%!assert (str2double ("-.1e-5"), -1e-6)
854%!testif ; ! __have_feature__ ("LLVM_LIBCXX")
855%! assert (str2double (char ("1", "2 3", "4i")), [1; NaN; 4i]);
856%!testif HAVE_LLVM_LIBCXX <47413>
857%! ## Same test code as above, intended only for test statistics with libc++.
858%! assert (str2double (char ("1", "2 3", "4i")), [1; NaN; 4i]);
859%!assert (str2double ("1,222.5"), 1222.5)
860%!assert (str2double ("i"), i)
861%!assert (str2double ("2j"), 2i)
862%!assert (str2double ("2 + j"), 2+j)
863%!assert (str2double ("i*2 + 3"), 3+2i)
864%!assert (str2double (".5*i + 3.5"), 3.5+0.5i)
865%!assert (str2double ("1e-3 + i*.25"), 1e-3 + 0.25i)
866%!assert (str2double (char ("2 + j","1.25e-3","-05")), [2+i; 1.25e-3; -5])
867%!assert (str2double ({"2 + j","1.25e-3","-05"}), [2+i, 1.25e-3, -5])
868%!assert (str2double (1), NaN)
869%!assert (str2double ("1 2 3 4"), NaN)
870%!assert (str2double ("Hello World"), NaN)
871%!assert (str2double ("NaN"), NaN)
872%!assert (str2double ("NA"), NA)
873%!assert (str2double ("Inf"), Inf)
874%!assert (str2double ("iNF"), Inf)
875%!assert (str2double ("-Inf"), -Inf)
876%!assert (str2double ("Inf*i"), complex (0, Inf))
877%!assert (str2double ("iNF*i"), complex (0, Inf))
878%!assert (str2double ("NaN + Inf*i"), complex (NaN, Inf))
879%!assert (str2double ("Inf - Inf*i"), complex (Inf, -Inf))
880%!assert (str2double ("-i*NaN - Inf"), complex (-Inf, -NaN))
881%!testif ; ! __have_feature__ ("LLVM_LIBCXX")
882%! assert (str2double ({"abc", "4i"}), [NaN + 0i, 4i]);
883%!testif HAVE_LLVM_LIBCXX <47413>
884%! assert (str2double ({"abc", "4i"}), [NaN + 0i, 4i]);
885%!testif ; ! __have_feature__ ("LLVM_LIBCXX")
886%! assert (str2double ({2, "4i"}), [NaN + 0i, 4i]);
887%!testif HAVE_LLVM_LIBCXX <47413>
888%! assert (str2double ({2, "4i"}), [NaN + 0i, 4i]);
889%!assert (str2double (zeros (3,1,2)), NaN)
890%!assert (str2double (''), NaN)
891%!assert (str2double ([]), NaN)
892%!assert (str2double (char (zeros (3,0))), NaN)
893%!assert (str2double ("1.000444"), 1.000444)
894%!assert (str2double ("1e999"), Inf)
895%!assert (str2double ("-1e999"), -Inf)
896*/
897
898DEFUN (__native2unicode__, args, ,
899 doc: /* -*- texinfo -*-
900@deftypefn {} {@var{utf8_str} =} __native2unicode__ (@var{native_bytes}, @var{codepage})
901Convert byte stream @var{native_bytes} to UTF-8 using @var{codepage}.
902
903@seealso{native2unicode, __unicode2native__}
904@end deftypefn */)
905{
906 if (args(0).is_string ())
907 return ovl (args(0));
908
909 std::string tmp = args(1).string_value ();
910 const char *codepage
911 = (tmp.empty () ? octave_locale_charset_wrapper () : tmp.c_str ());
912
913 charNDArray native_bytes = args(0).char_array_value ();
914
915 const char *src = native_bytes.data ();
916 std::size_t srclen = native_bytes.numel ();
917
918 std::size_t length;
919 uint8_t *utf8_str = nullptr;
920
921 utf8_str = octave_u8_conv_from_encoding (codepage, src, srclen, &length);
922
923 if (! utf8_str)
924 {
925 if (errno == ENOSYS)
926 error ("native2unicode: iconv() is not supported. Installing GNU "
927 "libiconv and then re-compiling Octave could fix this.");
928 else
929 error ("native2unicode: converting from codepage '%s' to UTF-8: %s",
930 codepage, std::strerror (errno));
931 }
932
933 unwind_action free_utf8_str ([utf8_str] () { ::free (utf8_str); });
934
935 octave_idx_type len = length;
936
937 charNDArray retval (dim_vector (1, len));
938
939 for (octave_idx_type i = 0; i < len; i++)
940 retval.xelem (i) = utf8_str[i];
941
942 return ovl (retval);
943}
944
945DEFUN (__unicode2native__, args, ,
946 doc: /* -*- texinfo -*-
947@deftypefn {} {@var{native_bytes} =} __unicode2native__ (@var{utf8_str}, @var{codepage})
948Convert UTF-8 string @var{utf8_str} to byte stream @var{native_bytes} using
949@var{codepage}.
950
951@seealso{unicode2native, __native2unicode__}
952@end deftypefn */)
953{
954 std::string tmp = args(1).string_value ();
955 const char *codepage
956 = (tmp.empty () ? octave_locale_charset_wrapper () : tmp.c_str ());
957
958 charNDArray utf8_str = args(0).char_array_value ();
959
960 const uint8_t *src = reinterpret_cast<const uint8_t *> (utf8_str.data ());
961 std::size_t srclen = utf8_str.numel ();
962
963 std::size_t length;
964 char *native_bytes = nullptr;
965
966 native_bytes = octave_u8_conv_to_encoding (codepage, src, srclen, &length);
967
968 if (! native_bytes)
969 {
970 if (errno == ENOSYS)
971 error ("unicode2native: iconv() is not supported. Installing GNU "
972 "libiconv and then re-compiling Octave could fix this.");
973 else
974 error ("unicode2native: converting from UTF-8 to codepage '%s': %s",
975 codepage, std::strerror (errno));
976 }
977
978 unwind_action free_native_bytes ([native_bytes] () { ::free (native_bytes); });
979
980 octave_idx_type len = length;
981
982 uint8NDArray retval (dim_vector (1, len));
983
984 for (octave_idx_type i = 0; i < len; i++)
985 retval.xelem (i) = native_bytes[i];
986
987 return ovl (retval);
988}
989
990DEFUN (__locale_charset__, , ,
991 doc: /* -*- texinfo -*-
992@deftypefn {} {@var{charset} =} __locale_charset__ ()
993Return the identifier for the charset used if the encoding is set to
994@qcode{"locale"}.
995@end deftypefn */)
996{
997 const char *charset = octave_locale_charset_wrapper ();
998 std::string charset_str (charset);
999 return ovl (charset_str);
1000}
1001
1002DEFUN (unicode_idx, args, ,
1003 doc: /* -*- texinfo -*-
1004@deftypefn {} {@var{idx} =} unicode_idx (@var{str})
1005Return an array with the indices for each UTF-8 encoded character in @var{str}.
1006
1007@example
1008@group
1009unicode_idx ("aäbc")
1010 @xresult{} [1, 2, 2, 3, 4]
1011@end group
1012@end example
1013
1014@end deftypefn */)
1015{
1016 if (args.length () != 1)
1017 print_usage ();
1018
1019 charNDArray str = args(0).xchar_array_value ("STR must be a string");
1020 Array<octave_idx_type> p (dim_vector (str.ndims (), 1));
1021 charNDArray str_p;
1022 if (str.ndims () > 1)
1023 {
1024 for (octave_idx_type i=0; i < str.ndims (); i++)
1025 p(i) = i;
1026 p(0) = 1;
1027 p(1) = 0;
1028 str_p = str.permute (p);
1029 }
1030
1031 const uint8_t *src = reinterpret_cast<const uint8_t *> (str_p.data ());
1032 octave_idx_type srclen = str.numel ();
1033
1034 NDArray idx (str_p.dims ());
1035
1036 octave_idx_type u8_char_num = 1;
1037 for (octave_idx_type i = 0; i < srclen; u8_char_num++)
1038 {
1039 int mblen = octave_u8_strmblen_wrapper (src + i);
1040 if (mblen < 1)
1041 mblen = 1;
1042 for (octave_idx_type j = 0; j < mblen; j++)
1043 idx(i+j) = u8_char_num;
1044 i += mblen;
1045 }
1046
1047 return ovl (str.ndims () > 1 ? idx.permute (p, true) : idx);
1048}
1049
1050/*
1051%!assert (unicode_idx (["aäou"; "Ä∞"]), [1 2 2 3 4; 5 5 6 6 6])
1052*/
1053
1054DEFUN (__unicode_length__, args, ,
1055 doc: /* -*- texinfo -*-
1056@deftypefn {} {@var{len} =} __unicode_length__ (@var{str})
1057Return number of Unicode code points in @var{str}.
1058
1059The input @var{str} must be a UTF-8 encoded character vector or cell string.
1060
1061@example
1062@group
1063length ("aäbc")
1064 @xresult{} 5
1065__unicode_length__ ("aäbc")
1066 @xresult{} 4
1067@end group
1068@end example
1069
1070@end deftypefn */)
1071{
1072 if (args.length () != 1)
1073 print_usage ();
1074
1075 bool arg_char = args(0).is_char_matrix ();
1076
1077 if (! arg_char && ! args(0).iscellstr ())
1078 error ("STR must be a character array or cell string.");
1079
1080 octave_value_list retval;
1081
1082 if (arg_char)
1083 {
1084 charNDArray str = args(0).char_array_value ();
1085 Array<octave_idx_type> p (dim_vector (str.ndims (), 1));
1086 if (str.ndims () > 1)
1087 {
1088 for (octave_idx_type i=0; i < str.ndims (); i++)
1089 p(i) = i;
1090 p(0) = 1;
1091 p(1) = 0;
1092 str = str.permute (p);
1093 }
1094
1095 const uint8_t *src = reinterpret_cast<const uint8_t *> (str.data ());
1096 octave_idx_type mbsnlen = octave_u8_mbsnlen_wrapper (src, str.numel ());
1097
1098 retval = ovl (mbsnlen);
1099 }
1100 else
1101 {
1102 const Array<std::string> cellstr = args(0).cellstr_value ();
1103 NDArray output (args(0).dims (), false);
1104 for (octave_idx_type i = 0; i < cellstr.numel (); i++)
1105 {
1106 const uint8_t *src
1107 = reinterpret_cast<const uint8_t *> (cellstr(i).c_str ());
1108 output(i) = octave_u8_mbsnlen_wrapper (src, cellstr(i).size ());
1109 }
1110
1111 retval = ovl (output);
1112 }
1113
1114 return retval;
1115}
1116
1117/*
1118%!assert (__unicode_length__ (""), 0)
1119%!assert (__unicode_length__ ("aäbc"), 4)
1120%!assert (__unicode_length__ (["aä"; "öo"]), 4)
1121%!assert (__unicode_length__ ({"aäbc", "abc"}), [4, 3])
1122*/
1123
1124DEFUN (__u8_validate__, args, ,
1125 doc: /* -*- texinfo -*-
1126@deftypefn {} {@var{out_str} =} __u8_validate__ (in_str, mode)
1127Return string with valid UTF-8.
1128
1129On encountering invalid UTF-8 in @var{in_str}, the bytes are either replaced by
1130the replacement character @qcode{"�"} (if @var{mode} is omitted or is the
1131string @qcode{"replace"}) or interpreted as the Unicode code points
1132U+0080–U+00FF with the same value as the byte (if @var{mode} is the string
1133@qcode{"unicode"}), thus interpreting the bytes according to ISO-8859-1.
1134@end deftypefn */)
1135{
1136 int nargin = args.length ();
1137
1138 if (nargin < 1 || nargin > 2)
1139 print_usage ();
1140
1141 // Input check
1142 std::string in_str =
1143 args(0).xstring_value ("__u8_validate__: IN_STR must be a string");
1144
1145 std::string mode = "replace";
1146 if (nargin == 2)
1147 mode = args(1).xstring_value ("__u8_validate__: MODE must be a string");
1148
1149 string::u8_fallback_type fb_type;
1150 if (mode == "replace")
1151 fb_type = string::U8_REPLACEMENT_CHAR;
1152 else if (mode == "unicode")
1153 fb_type = string::U8_ISO_8859_1;
1154 else
1155 error (R"(__u8_validate__: MODE must be either "replace" or "unicode")");
1156
1157 string::u8_validate ("__u8_validate__", in_str, fb_type);
1158
1159 return ovl (in_str);
1160}
1161
1162DEFUN (newline, args, ,
1163 doc: /* -*- texinfo -*-
1164@deftypefn {} {@var{c} =} newline
1165Return the character corresponding to a newline.
1166
1167This is equivalent to @qcode{"@backslashchar{}n"}.
1168
1169Example Code
1170
1171@example
1172@group
1173joined_string = [newline "line1" newline "line2"]
1174@xresult{}
1175line1
1176line2
1177@end group
1178@end example
1179
1180@seealso{strcat, strjoin, strsplit}
1181@end deftypefn */)
1182{
1183 if (args.length () != 0)
1184 print_usage ();
1185
1186 static octave_value_list retval = ovl ("\n");
1187
1188 return retval;
1189}
1190
1191/*
1192%!assert (newline (), "\n")
1193
1194%!error newline (1)
1195## FIXME: The next error() test requires a semicolon at EOL until
1196## bug #59265 is resolved.
1197%!error [a, b] = newline ();
1198*/
1199
1200DEFUN (list_in_columns, args, ,
1201 doc: /* -*- texinfo -*-
1202@deftypefn {} {@var{str} =} list_in_columns (@var{arg}, @var{width}, @var{prefix})
1203Return a string containing the elements of @var{arg} listed in columns with
1204an overall maximum width of @var{width} and optional prefix @var{prefix}.
1205
1206The argument @var{arg} must be a cell array of character strings or a
1207character array.
1208
1209If @var{width} is not specified or is an empty matrix, or less than or equal
1210to zero, the width of the terminal screen is used. Newline characters are
1211used to break the lines in the output string. For example:
1212@c Set example in small font to prevent overfull line
1213
1214@smallexample
1215@group
1216list_in_columns (@{"abc", "def", "ghijkl", "mnop", "qrs", "tuv"@}, 20)
1217 @xresult{} abc mnop
1218 def qrs
1219 ghijkl tuv
1220
1221whos ans
1222 @xresult{}
1223 Variables in the current scope:
1224
1225 Attr Name Size Bytes Class
1226 ==== ==== ==== ===== =====
1227 ans 1x37 37 char
1228
1229 Total is 37 elements using 37 bytes
1230@end group
1231@end smallexample
1232
1233@seealso{terminal_size}
1234@end deftypefn */)
1235{
1236 int nargin = args.length ();
1237
1238 if (nargin < 1 || nargin > 3)
1239 print_usage ();
1240
1241 string_vector s = args(0).xstring_vector_value ("list_in_columns: ARG must be a cellstr or char array");
1242
1243 int width = -1;
1244
1245 if (nargin > 1 && ! args(1).isempty ())
1246 width = args(1).strict_int_value ("list_in_columns: WIDTH must be an integer");
1247
1248 std::string prefix;
1249
1250 if (nargin > 2)
1251 prefix = args(2).xstring_value ("list_in_columns: PREFIX must be a string");
1252
1253 std::ostringstream buf;
1254
1255 s.list_in_columns (buf, width, prefix);
1256
1257 return ovl (buf.str ());
1258}
1259
1260/*
1261%!test
1262%! input = {"abc", "def", "ghijkl", "mnop", "qrs", "tuv"};
1263%! result = "abc mnop\ndef qrs\nghijkl tuv\n";
1264%! assert (list_in_columns (input, 20), result);
1265%!test
1266%! input = char ("abc", "def", "ghijkl", "mnop", "qrs", "tuv");
1267%! result = "abc mnop \ndef qrs \nghijkl tuv \n";
1268%! assert (list_in_columns (input, 20), result);
1269%!test
1270%! input = char ("abc", "def", "ghijkl", "mnop", "qrs", "tuv");
1271%! result = " abc mnop \n def qrs \n ghijkl tuv \n";
1272%! assert (list_in_columns (input, 20, " "), result);
1273
1274%!error list_in_columns ()
1275%!error list_in_columns (["abc", "def"], 20, 2)
1276%!error list_in_columns (["abc", "def"], 20, " ", 3)
1277%!error <list_in_columns: WIDTH must be an integer> list_in_columns (["abc", "def"], "a")
1278*/
1279
1280OCTAVE_END_NAMESPACE(octave)
N Dimensional Array with copy-on-write semantics.
Definition Array-base.h:130
const dim_vector & dims() const
Return a const-reference so that dims ()(i) works efficiently.
Definition Array-base.h:529
T & xelem(octave_idx_type n)
Size of the specified dimension.
Definition Array-base.h:547
int ndims() const
Size of the specified dimension.
Definition Array-base.h:701
Array< T, Alloc > permute(const Array< octave_idx_type > &vec, bool inv=false) const
Size of the specified dimension.
const T * data() const
Size of the specified dimension.
Definition Array-base.h:687
octave_idx_type numel() const
Number of elements in the array.
Definition Array-base.h:440
Definition Cell.h:41
bool iscellstr() const
Definition Cell.cc:126
MArray< T > permute(const Array< octave_idx_type > &vec, bool inv=false) const
Definition MArray.h:95
Vector representing the dimensions (size) of an Array.
Definition dim-vector.h:92
octave_idx_type length() const
Definition ovl.h:111
Cell cell_value() const
Array< std::string > cellstr_value() const
Definition ov.h:989
bool is_string() const
Definition ov.h:635
charNDArray char_array_value(bool frc_str_conv=false) const
Definition ov.h:904
bool iscell() const
Definition ov.h:602
octave_idx_type numel() const
Definition ov.h:557
string_vector string_vector_value(bool pad=false) const
Definition ov.h:984
octave_idx_type length() const
octave_value convert_to_str(bool pad=false, bool force=false, char type='\'') const
Definition ov.h:1320
bool iscellstr() const
Definition ov.h:605
dim_vector dims() const
Definition ov.h:539
octave_idx_type max_length() const
Definition str-vec.h:77
std::ostream & list_in_columns(std::ostream &, int width=0, const std::string &prefix="") const
Definition str-vec.cc:201
Array< U > map(F fcn) const
Definition str-vec.h:143
octave_idx_type numel() const
Definition str-vec.h:98
OCTAVE_BEGIN_NAMESPACE(octave) static octave_value daspk_fcn
void print_usage()
Definition defun-int.h:72
#define DEFUN(name, args_name, nargout_name, doc)
Macro to define a builtin function.
Definition defun.h:56
#define DEFUNX(name, fname, args_name, nargout_name, doc)
Macro to define a builtin function with certain internal name.
Definition defun.h:85
void error(const char *fmt,...)
Definition error.cc:1008
const char * octave_locale_charset_wrapper(void)
std::complex< double > Complex
Definition oct-cmplx.h:33
bool strncmp(const T &str_a, const T &str_b, const typename T::size_type n)
True if the first N characters are the same.
bool strcmp(const T &str_a, const T &str_b)
Octave string utility functions.
Complex str2double(const std::string &str_arg)
void free(void *)
octave_value_list ovl(const OV_Args &... args)
Construct an octave_value_list with less typing.
Definition ovl.h:217
octave_value_list Fstrcmpi(const octave_value_list &args, int)
Definition strfns.cc:708
octave_value_list Fstrncmpi(const octave_value_list &args, int)
Definition strfns.cc:744
char * octave_u8_conv_to_encoding(const char *tocode, const uint8_t *src, size_t srclen, size_t *lengthp)
uint8_t * octave_u8_conv_from_encoding(const char *fromcode, const char *src, size_t srclen, size_t *lengthp)
int octave_u8_strmblen_wrapper(const uint8_t *src)
size_t octave_u8_mbsnlen_wrapper(const uint8_t *src, size_t n)
F77_RET_T len
Definition xerbla.cc:61