comparison src/strfns.cc @ 10108:06e11df4592d

implement built-in strcmpi/strncmpi, reduce some code duplication
author Jaroslav Hajek <highegg@gmail.com>
date Thu, 14 Jan 2010 13:48:20 +0100
parents c2923c27c877
children cd96d29c5efa
comparison
equal deleted inserted replaced
10107:fd262afea1d1 10108:06e11df4592d
319 %!assert (ischar (1), logical (0)); 319 %!assert (ischar (1), logical (0));
320 %!error <Invalid call to ischar.*> ischar (); 320 %!error <Invalid call to ischar.*> ischar ();
321 321
322 */ 322 */
323 323
324 DEFUN (strcmp, args, , 324 static octave_value
325 "-*- texinfo -*-\n\ 325 do_strcmp_fun (const octave_value& arg0, const octave_value& arg1,
326 @deftypefn {Built-in Function} {} strcmp (@var{s1}, @var{s2})\n\ 326 octave_idx_type n, const char *fcn_name,
327 Return 1 if the character strings @var{s1} and @var{s2} are the same,\n\ 327 bool (*array_op) (const charNDArray&, const charNDArray&, octave_idx_type),
328 and 0 otherwise.\n\ 328 bool (*str_op) (const std::string&, const std::string&, octave_idx_type))
329 \n\ 329
330 If either @var{s1} or @var{s2} is a cell array of strings, then an array\n\
331 of the same size is returned, containing the values described above for\n\
332 every member of the cell array. The other argument may also be a cell\n\
333 array of strings (of the same size or with only one element), char matrix\n\
334 or character string.\n\
335 \n\
336 @strong{Caution:} For compatibility with @sc{matlab}, Octave's strcmp\n\
337 function returns 1 if the character strings are equal, and 0 otherwise.\n\
338 This is just the opposite of the corresponding C library function.\n\
339 @seealso{strcmpi, strncmp, strncmpi}\n\
340 @end deftypefn")
341 { 330 {
342 octave_value retval; 331 octave_value retval;
343 332
344 if (args.length () == 2) 333 bool s1_string = arg0.is_string ();
334 bool s1_cell = arg0.is_cell ();
335 bool s2_string = arg1.is_string ();
336 bool s2_cell = arg1.is_cell ();
337
338 if (s1_string && s2_string)
339 retval = array_op (arg0.char_array_value (), arg1.char_array_value (), n);
340 else if ((s1_string && s2_cell) || (s1_cell && s2_string))
345 { 341 {
346 bool s1_string = args(0).is_string (); 342 octave_value str_val, cell_val;
347 bool s1_cell = args(0).is_cell (); 343
348 bool s2_string = args(1).is_string (); 344 if (s1_string)
349 bool s2_cell = args(1).is_cell (); 345 {
350 346 str_val = arg0;
351 if (s1_string && s2_string) 347 cell_val = arg1;
352 { 348 }
353 // Must match exactly in all dimensions. 349 else
354 350 {
355 const dim_vector dv1 = args(0).dims (); 351 str_val = arg1;
356 const dim_vector dv2 = args(1).dims (); 352 cell_val = arg0;
357 353 }
358 if (dv1.length () == dv2.length ()) 354
359 { 355 const Cell cell = cell_val.cell_value ();
360 for (octave_idx_type i = 0; i < dv1.length (); i++) 356 const string_vector str = str_val.all_strings ();
361 { 357 octave_idx_type r = str.rows ();
362 if (dv1(i) != dv2(i)) 358
363 { 359 if (r == 0 || r == 1)
364 retval = false; 360 {
365 return retval; 361 // Broadcast the string.
366 } 362
367 } 363 boolNDArray output (cell_val.dims (), false);
368 364
369 if (dv1(0) == 0) 365 std::string s = r == 0 ? std::string () : str[0];
370 retval = true; 366
371 else 367 if (cell_val.is_cellstr ())
372 { 368 {
373 const charNDArray s1 = args(0).char_array_value (); 369 const Array<std::string> cellstr = cell_val.cellstr_value ();
374 const charNDArray s2 = args(1).char_array_value (); 370 for (octave_idx_type i = 0; i < cellstr.length (); i++)
375 371 output(i) = str_op (cellstr(i), s, n);
376 for (octave_idx_type i = 0; i < dv1.numel (); i++) 372 }
377 { 373 else
378 if (s1(i) != s2(i)) 374 {
379 { 375 // FIXME: should we warn here?
380 retval = false; 376 for (octave_idx_type i = 0; i < cell.length (); i++)
381 return retval;
382 }
383 }
384
385 retval = true;
386 }
387 }
388 }
389 else if ((s1_string && s2_cell) || (s1_cell && s2_string))
390 {
391 octave_value str_val, cell_val;
392
393 if (s1_string)
394 {
395 str_val = args (0);
396 cell_val = args (1);
397 }
398 else
399 {
400 str_val = args (1);
401 cell_val = args (0);
402 }
403
404 const Cell cell = cell_val.cell_value ();
405 const string_vector str = str_val.all_strings ();
406 octave_idx_type r = str.rows ();
407
408 if (r == 0 || r == 1)
409 {
410 // Broadcast the string.
411
412 boolNDArray output (cell_val.dims (), false);
413
414 std::string s = r == 0 ? std::string () : str[0];
415
416 if (cell_val.is_cellstr ())
417 { 377 {
418 const Array<std::string> cellstr = cell_val.cellstr_value (); 378 if (cell(i).is_string ())
419 for (octave_idx_type i = 0; i < cellstr.length (); i++) 379 output(i) = str_op (cell(i).string_value (), s, n);
420 output(i) = cellstr(i) == s;
421 } 380 }
422 else 381 }
382
383 retval = output;
384 }
385 else if (r > 1)
386 {
387 if (cell.length () == 1)
388 {
389 // Broadcast the cell.
390
391 const dim_vector dv (r, 1);
392 boolNDArray output (dv, false);
393
394 if (cell(0).is_string ())
423 { 395 {
424 // FIXME: should we warn here? 396 const std::string str2 = cell(0).string_value ();
425 for (octave_idx_type i = 0; i < cell.length (); i++) 397
398 for (octave_idx_type i = 0; i < r; i++)
399 output(i) = str_op (str[i], str2, n);
400 }
401
402 retval = output;
403 }
404 else
405 {
406 // Must match in all dimensions.
407
408 boolNDArray output (cell.dims (), false);
409
410 if (cell.length () == r)
411 {
412 if (cell_val.is_cellstr ())
426 { 413 {
427 if (cell(i).is_string ()) 414 const Array<std::string> cellstr = cell_val.cellstr_value ();
428 output(i) = (cell(i).string_value () == s);
429 }
430 }
431
432 retval = output;
433 }
434 else if (r > 1)
435 {
436 if (cell.length () == 1)
437 {
438 // Broadcast the cell.
439
440 const dim_vector dv (r, 1);
441 boolNDArray output (dv, false);
442
443 if (cell(0).is_string ())
444 {
445 const std::string str2 = cell(0).string_value ();
446
447 for (octave_idx_type i = 0; i < r; i++)
448 output(i) = (str[i] == str2);
449 }
450
451 retval = output;
452 }
453 else
454 {
455 // Must match in all dimensions.
456
457 boolNDArray output (cell.dims (), false);
458
459 if (cell.length () == r)
460 {
461 if (cell_val.is_cellstr ())
462 {
463 const Array<std::string> cellstr = cell_val.cellstr_value ();
464 for (octave_idx_type i = 0; i < cellstr.length (); i++)
465 output(i) = str[i] == cellstr(i);
466 }
467 else
468 {
469 // FIXME: should we warn here?
470 for (octave_idx_type i = 0; i < r; i++)
471 {
472 if (cell(i).is_string ())
473 output(i) = (str[i] == cell(i).string_value ());
474 }
475 }
476
477 retval = output;
478 }
479 else
480 retval = false;
481 }
482 }
483 }
484 else if (s1_cell && s2_cell)
485 {
486 octave_value cell1_val, cell2_val;
487 octave_idx_type r1 = args(0).numel (), r2;
488
489 if (r1 == 1)
490 {
491 // Make the singleton cell2.
492
493 cell1_val = args(1);
494 cell2_val = args(0);
495 }
496 else
497 {
498 cell1_val = args(0);
499 cell2_val = args(1);
500 }
501
502 const Cell cell1 = cell1_val.cell_value ();
503 const Cell cell2 = cell2_val.cell_value ();
504 r1 = cell1.numel ();
505 r2 = cell2.numel ();
506
507 const dim_vector size1 = cell1.dims ();
508 const dim_vector size2 = cell2.dims ();
509
510 boolNDArray output (size1, false);
511
512 if (r2 == 1)
513 {
514 // Broadcast cell2.
515
516 if (cell2(0).is_string ())
517 {
518 const std::string str2 = cell2(0).string_value ();
519
520 if (cell1_val.is_cellstr ())
521 {
522 const Array<std::string> cellstr = cell1_val.cellstr_value ();
523 for (octave_idx_type i = 0; i < cellstr.length (); i++) 415 for (octave_idx_type i = 0; i < cellstr.length (); i++)
524 output(i) = cellstr(i) == str2; 416 output(i) = str_op (str[i], cellstr(i), n);
525 } 417 }
526 else 418 else
527 { 419 {
528 // FIXME: should we warn here? 420 // FIXME: should we warn here?
529 for (octave_idx_type i = 0; i < r1; i++) 421 for (octave_idx_type i = 0; i < r; i++)
530 { 422 {
531 if (cell1(i).is_string ()) 423 if (cell(i).is_string ())
532 { 424 output(i) = str_op (str[i], cell(i).string_value (), n);
533 const std::string str1 = cell1(i).string_value ();
534 output(i) = (str1 == str2);
535 }
536 } 425 }
537 } 426 }
538 } 427
539 } 428 retval = output;
540 else 429 }
541 { 430 else
542 if (size1 != size2) 431 retval = false;
543 { 432 }
544 error ("strcmp: nonconformant cell arrays"); 433 }
545 return retval; 434 }
546 } 435 else if (s1_cell && s2_cell)
547 436 {
548 if (cell1.is_cellstr () && cell2.is_cellstr ()) 437 octave_value cell1_val, cell2_val;
438 octave_idx_type r1 = arg0.numel (), r2;
439
440 if (r1 == 1)
441 {
442 // Make the singleton cell2.
443
444 cell1_val = arg1;
445 cell2_val = arg0;
446 }
447 else
448 {
449 cell1_val = arg0;
450 cell2_val = arg1;
451 }
452
453 const Cell cell1 = cell1_val.cell_value ();
454 const Cell cell2 = cell2_val.cell_value ();
455 r1 = cell1.numel ();
456 r2 = cell2.numel ();
457
458 const dim_vector size1 = cell1.dims ();
459 const dim_vector size2 = cell2.dims ();
460
461 boolNDArray output (size1, false);
462
463 if (r2 == 1)
464 {
465 // Broadcast cell2.
466
467 if (cell2(0).is_string ())
468 {
469 const std::string str2 = cell2(0).string_value ();
470
471 if (cell1_val.is_cellstr ())
549 { 472 {
550 const Array<std::string> cellstr1 = cell1_val.cellstr_value (); 473 const Array<std::string> cellstr = cell1_val.cellstr_value ();
551 const Array<std::string> cellstr2 = cell2_val.cellstr_value (); 474 for (octave_idx_type i = 0; i < cellstr.length (); i++)
552 for (octave_idx_type i = 0; i < r1; i++) 475 output(i) = str_op (cellstr(i), str2, n);
553 output (i) = cellstr1(i) == cellstr2(i);
554 } 476 }
555 else 477 else
556 { 478 {
557 // FIXME: should we warn here? 479 // FIXME: should we warn here?
558 for (octave_idx_type i = 0; i < r1; i++) 480 for (octave_idx_type i = 0; i < r1; i++)
559 { 481 {
560 if (cell1(i).is_string () && cell2(i).is_string ()) 482 if (cell1(i).is_string ())
561 { 483 {
562 const std::string str1 = cell1(i).string_value (); 484 const std::string str1 = cell1(i).string_value ();
563 const std::string str2 = cell2(i).string_value (); 485 output(i) = str_op (str1, str2, n);
564 output(i) = (str1 == str2);
565 } 486 }
566 } 487 }
567 } 488 }
568 } 489 }
569 490 }
570 retval = output;
571 }
572 else 491 else
573 retval = false; 492 {
493 if (size1 != size2)
494 {
495 error ("%s: nonconformant cell arrays", fcn_name);
496 return retval;
497 }
498
499 if (cell1.is_cellstr () && cell2.is_cellstr ())
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 // If both args are arrays, dimensions may be significant.
530 static bool
531 strcmp_array_op (const charNDArray& s1, const charNDArray& s2, octave_idx_type)
532 {
533 return (s1.dims () == s2.dims ()
534 && std::equal (s1.data (), s1.data () + s1.numel (), s2.data ()));
535 }
536
537 // Otherwise, just use strings.
538 static bool
539 strcmp_str_op (const std::string& s1, const std::string& s2,
540 octave_idx_type)
541 {
542 return s1 == s2;
543 }
544
545 DEFUN (strcmp, args, ,
546 "-*- texinfo -*-\n\
547 @deftypefn {Built-in Function} {} strcmp (@var{s1}, @var{s2})\n\
548 Return 1 if the character strings @var{s1} and @var{s2} are the same,\n\
549 and 0 otherwise.\n\
550 \n\
551 If either @var{s1} or @var{s2} is a cell array of strings, then an array\n\
552 of the same size is returned, containing the values described above for\n\
553 every member of the cell array. The other argument may also be a cell\n\
554 array of strings (of the same size or with only one element), char matrix\n\
555 or character string.\n\
556 \n\
557 @strong{Caution:} For compatibility with @sc{matlab}, Octave's strcmp\n\
558 function returns 1 if the character strings are equal, and 0 otherwise.\n\
559 This is just the opposite of the corresponding C library function.\n\
560 @seealso{strcmpi, strncmp, strncmpi}\n\
561 @end deftypefn")
562 {
563 octave_value retval;
564
565 if (args.length () == 2)
566 {
567 retval = do_strcmp_fun (args (0), args (1), 0,
568 "strcmp", strcmp_array_op, strcmp_str_op);
574 } 569 }
575 else 570 else
576 print_usage (); 571 print_usage ();
577 572
578 return retval; 573 return retval;
619 %!assert (all (strcmp ({'foo'}, y) == [false; false])); 614 %!assert (all (strcmp ({'foo'}, y) == [false; false]));
620 %!assert (all (strcmp (y, {'foo'}) == [false; false])); 615 %!assert (all (strcmp (y, {'foo'}) == [false; false]));
621 %!assert (all (strcmp (y, {'foo'}) == [false; false])); 616 %!assert (all (strcmp (y, {'foo'}) == [false; false]));
622 */ 617 */
623 618
619 // Apparently, Matlab ignores the dims with strncmp. It also
620 static bool
621 strncmp_array_op (const charNDArray& s1, const charNDArray& s2, octave_idx_type n)
622 {
623 octave_idx_type l1 = s1.numel (), l2 = s2.numel ();
624 return (n > 0 && n <= l1 && n <= l2
625 && std::equal (s1.data (), s1.data () + n, s2.data ()));
626 }
627
628 // Otherwise, just use strings. Note that we neither extract substrings (which
629 // would mean a copy, at least in GCC), nor use string::compare (which is a
630 // 3-way compare).
631 static bool
632 strncmp_str_op (const std::string& s1, const std::string& s2, octave_idx_type n)
633 {
634 octave_idx_type l1 = s1.length (), l2 = s2.length ();
635 return (n > 0 && n <= l1 && n <= l2
636 && std::equal (s1.data (), s1.data () + n, s2.data ()));
637 }
638
624 DEFUN (strncmp, args, , 639 DEFUN (strncmp, args, ,
625 "-*- texinfo -*-\n\ 640 "-*- texinfo -*-\n\
626 @deftypefn {Built-in Function} {} strncmp (@var{s1}, @var{s2}, @var{n})\n\ 641 @deftypefn {Built-in Function} {} strncmp (@var{s1}, @var{s2}, @var{n})\n\
627 Return 1 if the first @var{n} characters of strings @var{s1} and @var{s2} are the same,\n\ 642 Return 1 if the first @var{n} characters of strings @var{s1} and @var{s2} are the same,\n\
628 and 0 otherwise.\n\ 643 and 0 otherwise.\n\
655 { 670 {
656 octave_value retval; 671 octave_value retval;
657 672
658 if (args.length () == 3) 673 if (args.length () == 3)
659 { 674 {
660 bool s1_string = args(0).is_string (); 675 octave_idx_type n = args(2).idx_type_value ();
661 bool s1_cell = args(0).is_cell (); 676
662 bool s2_string = args(1).is_string (); 677 if (! error_state)
663 bool s2_cell = args(1).is_cell (); 678 {
664 679 if (n > 0)
665 // Match only first n strings. 680 {
666 int n = args(2).int_value (); 681 retval = do_strcmp_fun (args(0), args(1), n, "strncmp",
667 682 strncmp_array_op, strncmp_str_op);
668 if (n <= 0) 683 }
669 { 684 else
670 error ("strncmp: N must be greater than 0"); 685 error ("strncmp: N must be greater than 0");
671 return retval; 686 }
672 }
673
674 if (s1_string && s2_string)
675 {
676 // The only restriction here is that each string has equal or
677 // greater than n characters
678
679 const dim_vector dv1 = args(0).dims ();
680 const dim_vector dv2 = args(1).dims ();
681
682 if (dv1.numel () >= n && dv2.numel () >= n)
683 {
684 // Follow Matlab in the sense that the first n characters of
685 // the two strings (in column major order) need to be the same.
686 charNDArray s1 = args(0).char_array_value ();
687 charNDArray s2 = args(1).char_array_value ();
688
689 for (int i = 0; i < n; i++)
690 {
691 if (s1(i) != s2(i))
692 {
693 retval = false;
694 return retval;
695 }
696 }
697
698 retval = true;
699 }
700 else
701 retval = false;
702 }
703 else if ((s1_string && s2_cell) || (s1_cell && s2_string))
704 {
705 string_vector str;
706 Cell cell;
707 octave_idx_type r, c;
708
709 if (s1_string)
710 {
711 str = args(0).all_strings ();
712 r = args(0).rows ();
713 c = args(0).columns ();
714 cell = args(1).cell_value ();
715 }
716 else
717 {
718 str = args(1).all_strings ();
719 r = args(1).rows ();
720 c = args(1).columns ();
721 cell = args(0).cell_value ();
722 }
723
724 if (r == 1)
725 {
726 // Broadcast the string.
727
728 boolNDArray output (cell.dims (), false);
729
730 if (c < n)
731 {
732 for (octave_idx_type i = 0; i < cell.length (); i++)
733 output(i) = false;
734 }
735 else
736 {
737 for (octave_idx_type i = 0; i < cell.length (); i++)
738 {
739 if (cell(i).is_string ())
740 {
741 const std::string str2 = cell(i).string_value ();
742
743 if (str2.length () >= n
744 && str2.compare (0, n, str[0], 0, n) == 0)
745 output(i) = true;
746 }
747 }
748 }
749
750 retval = output;
751 }
752 else if (r > 1)
753 {
754 if (cell.length () == 1)
755 {
756 // Broadcast the cell.
757
758 const dim_vector dv (r, 1);
759 boolNDArray output (dv, false);
760
761 if (cell(0).is_string () && c >= n)
762 {
763 const std::string str2 = cell(0).string_value ();
764
765 if (str2.length () >= n)
766 {
767 for (octave_idx_type i = 0; i < r; i++)
768 {
769 if (str[i].compare (0, n, str2, 0, n) == 0)
770 output(i) = true;
771 }
772 }
773 }
774
775 retval = output;
776 }
777 else
778 {
779 // Must match in all dimensions.
780
781 boolNDArray output (cell.dims (), false);
782
783 if (cell.numel () == r)
784 {
785 for (octave_idx_type i = 0; i < r; i++)
786 {
787 if (cell(i).is_string () && c >= n)
788 {
789 std::string str2 = cell(i).string_value ();
790
791 if (str2.length () >= n
792 && str2.compare (0, n, str[i], 0, n) == 0)
793 output(i) = true;
794 }
795 }
796
797 retval = output;
798 }
799 else
800 {
801 error ("strncmp: the number of rows of the string matrix must match the number of elements in the cell");
802 return retval;
803 }
804 }
805 }
806 }
807 else if (s1_cell && s2_cell)
808 {
809 Cell cell1;
810 Cell cell2;
811
812 octave_idx_type r1 = args(0).numel ();
813 octave_idx_type r2;
814
815 if (r1 == 1)
816 {
817 // Make the singleton cell2.
818
819 cell1 = args(1).cell_value ();
820 cell2 = args(0).cell_value ();
821 r1 = cell1.length ();
822 r2 = 1;
823 }
824 else
825 {
826 cell1 = args(0).cell_value ();
827 cell2 = args(1).cell_value ();
828 r2 = cell2.length ();
829 }
830
831 const dim_vector size1 = cell1.dims ();
832 const dim_vector size2 = cell2.dims ();
833
834 boolNDArray output (size1, false);
835
836 if (r2 == 1)
837 {
838 // Broadcast cell2.
839
840 if (cell2(0).is_string ())
841 {
842 const std::string str2 = cell2(0).string_value ();
843
844 for (octave_idx_type i = 0; i < r1; i++)
845 {
846 if (cell1(i).is_string ())
847 {
848 const std::string str1 = cell1(i).string_value ();
849
850 if (str1.length () >= n && str2.length () >= n
851 && str1.compare (0, n, str2, 0, n) == 0)
852 output(i) = true;
853 }
854 }
855 }
856 }
857 else
858 {
859 if (size1 != size2)
860 {
861 error ("strncmp: nonconformant cell arrays");
862 return retval;
863 }
864
865 for (octave_idx_type i = 0; i < r1; i++)
866 {
867 if (cell1(i).is_string () && cell2(i).is_string ())
868 {
869 const std::string str1 = cell1(i).string_value ();
870 const std::string str2 = cell2(i).string_value ();
871
872 if (str1.length () >= n && str2.length () >= n
873 && str1.compare (0, n, str2, 0, n) == 0)
874 output(i) = true;
875 }
876 }
877 }
878
879 retval = output;
880 }
881 else
882 retval = false;
883 } 687 }
884 else 688 else
885 print_usage (); 689 print_usage ();
886 690
887 return retval; 691 return retval;
897 %!assert (all (strncmp ({"abcd", "bca", "abc"},"abce", 3) == [1, 0, 1])) 701 %!assert (all (strncmp ({"abcd", "bca", "abc"},"abce", 3) == [1, 0, 1]))
898 %!assert (all (strncmp ({"abcd", "bca", "abc"},{"abcd", "bca", "abe"}, 3) == [1, 1, 0])) 702 %!assert (all (strncmp ({"abcd", "bca", "abc"},{"abcd", "bca", "abe"}, 3) == [1, 1, 0]))
899 %!assert (all (strncmp("abc", {"abcd", 10}, 2) == [1, 0])) 703 %!assert (all (strncmp("abc", {"abcd", 10}, 2) == [1, 0]))
900 */ 704 */
901 705
706 // case-insensitive character equality functor
707 struct icmp_char_eq : public std::binary_function<char, char, bool>
708 {
709 bool operator () (char x, char y) const
710 { return std::toupper (x) == std::toupper (y); }
711 };
712
713 // strcmpi is equivalent to strcmp in that it checks all dims.
714 static bool
715 strcmpi_array_op (const charNDArray& s1, const charNDArray& s2, octave_idx_type)
716 {
717 return (s1.dims () == s2.dims ()
718 && std::equal (s1.data (), s1.data () + s1.numel (), s2.data (),
719 icmp_char_eq ()));
720 }
721
722 // Ditto for string.
723 static bool
724 strcmpi_str_op (const std::string& s1, const std::string& s2,
725 octave_idx_type)
726 {
727 return (s1.size () == s2.size ()
728 && std::equal (s1.data (), s1.data () + s1.size (), s2.data (),
729 icmp_char_eq ()));
730 }
731
732 DEFUN (strcmpi, args, ,
733 "-*- texinfo -*-\n\
734 @deftypefn {Built-in Function} {} strcmpi (@var{s1}, @var{s2})\n\
735 Returns 1 if the character strings @var{s1} and @var{s2} are the same,\n\
736 disregarding case of alphabetic characters, and 0 otherwise.\n\
737 \n\
738 If either @var{s1} or @var{s2} is a cell array of strings, then an array\n\
739 of the same size is returned, containing the values described above for\n\
740 every member of the cell array. The other argument may also be a cell\n\
741 array of strings (of the same size or with only one element), char matrix\n\
742 or character string.\n\
743 \n\
744 @strong{Caution:} For compatibility with @sc{matlab}, Octave's strcmp\n\
745 function returns 1 if the character strings are equal, and 0 otherwise.\n\
746 This is just the opposite of the corresponding C library function.\n\
747 \n\
748 @strong{Caution:} National alphabets are not supported.\n\
749 @seealso{strcmp, strncmp, strncmpi}\n\
750 @end deftypefn")
751 {
752 octave_value retval;
753
754 if (args.length () == 2)
755 {
756 retval = do_strcmp_fun (args (0), args (1), 0,
757 "strcmpi", strcmpi_array_op, strcmpi_str_op);
758 }
759 else
760 print_usage ();
761
762 return retval;
763 }
764
765 /*
766 %!assert (strcmpi("abc123", "ABC123"), logical(1));
767 */
768
769 // Like strncmp.
770 static bool
771 strncmpi_array_op (const charNDArray& s1, const charNDArray& s2, octave_idx_type n)
772 {
773 octave_idx_type l1 = s1.numel (), l2 = s2.numel ();
774 return (n > 0 && n <= l1 && n <= l2
775 && std::equal (s1.data (), s1.data () + n, s2.data (),
776 icmp_char_eq ()));
777 }
778
779 // Ditto.
780 static bool
781 strncmpi_str_op (const std::string& s1, const std::string& s2, octave_idx_type n)
782 {
783 octave_idx_type l1 = s1.length (), l2 = s2.length ();
784 return (n > 0 && n <= l1 && n <= l2
785 && std::equal (s1.data (), s1.data () + n, s2.data (),
786 icmp_char_eq ()));
787 }
788
789 DEFUN (strncmpi, args, ,
790 "-*- texinfo -*-\n\
791 @deftypefn {Built-in Function} {} strncmp (@var{s1}, @var{s2}, @var{n})\n\
792 Returns 1 if the first @var{n} character of @var{s1} and @var{s2} are the same,\n\
793 disregarding case of alphabetic characters, and 0 otherwise.\n\
794 \n\
795 If either @var{s1} or @var{s2} is a cell array of strings, then an array\n\
796 of the same size is returned, containing the values described above for\n\
797 every member of the cell array. The other argument may also be a cell\n\
798 array of strings (of the same size or with only one element), char matrix\n\
799 or character string.\n\
800 \n\
801 @strong{Caution:} For compatibility with @sc{matlab}, Octave's strncmpi\n\
802 function returns 1 if the character strings are equal, and 0 otherwise.\n\
803 This is just the opposite of the corresponding C library function.\n\
804 \n\
805 @strong{Caution:} National alphabets are not supported.\n\
806 @seealso{strncmp, strcmp, strcmpi}\n\
807 @end deftypefn")
808 {
809 octave_value retval;
810
811 if (args.length () == 3)
812 {
813 octave_idx_type n = args(2).idx_type_value ();
814
815 if (! error_state)
816 {
817 if (n > 0)
818 {
819 retval = do_strcmp_fun (args(0), args(1), n, "strncmpi",
820 strncmpi_array_op, strncmpi_str_op);
821 }
822 else
823 error ("strncmp: N must be greater than 0");
824 }
825 }
826 else
827 print_usage ();
828
829 return retval;
830 }
831
832 /*
833 %!assert (strncmpi("abc123", "ABC456", 3), logical(1));
834 */
902 835
903 DEFUN (list_in_columns, args, , 836 DEFUN (list_in_columns, args, ,
904 "-*- texinfo -*-\n\ 837 "-*- texinfo -*-\n\
905 @deftypefn {Built-in Function} {} list_in_columns (@var{arg}, @var{width})\n\ 838 @deftypefn {Built-in Function} {} list_in_columns (@var{arg}, @var{width})\n\
906 Return a string containing the elements of @var{arg} listed in\n\ 839 Return a string containing the elements of @var{arg} listed in\n\