Skip to content

Commit aad3512

Browse files
committed
New function: find-any(string, function)
This is like string-search-set from cl-strings, but instead of a string-search-not-set version, you just pass complement(test).
1 parent 74732ba commit aad3512

3 files changed

Lines changed: 57 additions & 37 deletions

File tree

library.dylan

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,11 +65,11 @@ define module strings
6565
pad-left,
6666
pad-right,
6767

68+
find-any,
6869
find-substring,
6970
replace-substrings,
7071
count-substrings,
7172

72-
// skip-whitespace -- position-if(whitespace?, <sequence>)
7373
// override find(...) in common-extensions
7474

7575
split-lines;

strings.dylan

Lines changed: 44 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -627,15 +627,17 @@ define method strip
627627
end: epos :: <integer> = string.size)
628628
=> (new-string :: <string>)
629629
let untest = complement(test);
630-
let left = %find-key(string, untest, start, epos);
630+
let left = find-any(string, untest, start: start, end: epos);
631631
if (~left)
632632
""
633633
else
634-
let right = %find-key-from-end(string, untest, start, epos) | left;
635-
if (left == 0 & right == string.size)
634+
// If left is not #f then right will also not be #f.
635+
let right :: <integer>
636+
= find-any(string, untest, start: start, end: epos, from-end?: #t);
637+
if (left == 0 & right == (string.size - 1))
636638
string
637639
else
638-
copy-sequence(string, start: left, end: right)
640+
copy-sequence(string, start: left, end: right + 1)
639641
end
640642
end if
641643
end method strip;
@@ -649,7 +651,8 @@ define method strip-left
649651
start :: <integer> = 0,
650652
end: epos :: <integer> = string.size)
651653
=> (new-string :: <string>)
652-
let left :: <integer> = %find-key(string, complement(test), start, epos) | epos;
654+
let left :: <integer>
655+
= find-any(string, complement(test), start: start, end: epos) | epos;
653656
if (left == 0 & epos == string.size)
654657
string
655658
else
@@ -666,11 +669,14 @@ define method strip-right
666669
start :: <integer> = 0,
667670
end: epos :: <integer> = string.size)
668671
=> (new-string :: <string>)
669-
let right = %find-key-from-end(string, complement(test), start, epos) | start;
670-
if (start == 0 & right == string.size)
671-
string
672-
else
673-
copy-sequence(string, start: start, end: right)
672+
let right = find-any(string, complement(test), from-end?: #t, start: start, end: epos);
673+
case
674+
~right
675+
=> "";
676+
start == 0 & right == (string.size - 1)
677+
=> string;
678+
otherwise
679+
=> copy-sequence(string, start: start, end: right + 1)
674680
end
675681
end method strip-right;
676682

@@ -740,32 +746,6 @@ define inline function range-check
740746
end;
741747

742748

743-
define inline function %find-key-from-end
744-
(string :: <string>, test :: <function>, start :: <integer>, epos :: <integer>)
745-
=> (key :: false-or(<integer>))
746-
iterate loop (i = epos - 1)
747-
if (i >= start)
748-
xif (test(string[i]),
749-
i + 1,
750-
loop(i - 1))
751-
end
752-
end iterate
753-
end function %find-key-from-end;
754-
755-
756-
// Like find-key but accepts start/end args. Would like to add them to find-key.
757-
define function %find-key
758-
(seq :: <sequence>, test :: <function>, start :: <integer>, epos :: <integer>)
759-
=> (key :: false-or(<integer>))
760-
iterate loop (i = start)
761-
if (i < epos)
762-
xif(test(seq[i]),
763-
i,
764-
loop(i + 1))
765-
end
766-
end
767-
end function %find-key;
768-
769749
// Because every? doesn't have start/end parameters.
770750
define inline function %every?
771751
(test :: <function>, string :: <string>, bpos :: <integer>, epos :: <integer>)
@@ -775,3 +755,31 @@ define inline function %every?
775755
#t)
776756
end
777757
end function %every?;
758+
759+
760+
// Find the index of the first char in `string` that is a member of `charset`.
761+
define generic find-any (string :: <string>, test :: <function>,
762+
#key start, end: epos, from-end?)
763+
=> (index :: false-or(<integer>));
764+
765+
define method find-any (string :: <string>, test :: <function>,
766+
#key start: bpos :: <integer> = 0,
767+
end: epos :: <integer> = string.size,
768+
from-end? :: <boolean>)
769+
=> (index :: false-or(<integer>))
770+
block (return)
771+
if (from-end?)
772+
for (i from epos - 1 to bpos by -1)
773+
if (test(string[i]))
774+
return(i);
775+
end;
776+
end;
777+
else
778+
for (i from bpos below epos)
779+
if (test(string[i]))
780+
return(i);
781+
end;
782+
end;
783+
end;
784+
end
785+
end method;

tests/strings-test-suite.dylan

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -488,6 +488,18 @@ define test test-split-lines ()
488488
check-equal("j", split-lines("\na"), #["", "a"]);
489489
end test;
490490

491+
define test test-find-any ()
492+
assert-false(find-any("abc", whitespace?));
493+
assert-equal(1, find-any("a b c", whitespace?));
494+
assert-equal(3, find-any("a b c", whitespace?, from-end?: #t));
495+
assert-equal(0, find-any("a b c", complement(whitespace?)));
496+
assert-equal(4, find-any("a b c", complement(whitespace?), from-end?: #t));
497+
assert-equal(3, find-any("a b c", whitespace?, start: 2));
498+
assert-equal(#f, find-any("a b c", whitespace?, start: 2, end: 2));
499+
assert-equal(1, find-any("a b c", whitespace?, end: 2, from-end?: #t));
500+
assert-equal(#f, find-any("a b c", whitespace?, start: 2, end: 2, from-end?: #t));
501+
end test;
502+
491503
////
492504
//// Benchmarks
493505
////

0 commit comments

Comments
 (0)