Mercurial > octave-nkf
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\ |