[m-rev.] for review: Add case-insensitive string compare predicate.

Peter Wang novalazy at gmail.com
Mon Jun 20 14:13:14 AEST 2016


Suggestions for a better name?
---

library/string.m:
	Add string.compare_ci_ascii predicate,
	i.e. case-insensitive in the ASCII range.

NEWS:
	Announce addition.
---
 NEWS             |  1 +
 library/string.m | 45 +++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 46 insertions(+)

diff --git a/NEWS b/NEWS
index 99bb129..32423b5 100644
--- a/NEWS
+++ b/NEWS
@@ -256,6 +256,7 @@ Changes to the Mercury standard library:
    - from_utf8_code_unit_list/2
    - from_utf16_code_unit_list/2
    - det_remove_prefix/3
+   - compare_ci_ascii/3
 
 * The following predicates have been added to the map module:
 
diff --git a/library/string.m b/library/string.m
index c13f7d4..36d0c37 100644
--- a/library/string.m
+++ b/library/string.m
@@ -456,6 +456,15 @@
     %
 :- pred contains_char(string::in, char::in) is semidet.
 
+    % compare_ci_ascii(Res, X, Y):
+    %
+    % Compare two strings by code point order, ignoring the case of letters
+    % (A-Z, a-z) in the ASCII range.
+    % Equivalent to `compare(Res, to_lower(X), to_lower(Y))'
+    % but more efficient.
+    %
+:- pred compare_ci_ascii(comparison_result::uo, string::in, string::in) is det.
+
     % prefix_length(Pred, String):
     %
     % The length (in code units) of the maximal prefix of `String' consisting
@@ -3143,6 +3152,42 @@ contains_char(Str, Char, I) :-
 
 %---------------------%
 
+compare_ci_ascii(Res, X, Y) :-
+    compare_ci_ascii_loop(X, Y, 0, Res).
+
+:- pred compare_ci_ascii_loop(string::in, string::in, int::in,
+    comparison_result::uo) is det.
+
+compare_ci_ascii_loop(X, Y, I, Res) :-
+    ( if unsafe_index_next(X, I, IX, CharX) then
+        ( if unsafe_index_next(Y, I, _IY, CharY) then
+            char.to_lower(CharX, LowerCharX),
+            char.to_lower(CharY, LowerCharY),
+            compare(CharRes, LowerCharX, LowerCharY),
+            (
+                CharRes = (=),
+                % CharX = CharY, or both are in the ASCII range.
+                % In either case, we must have IX = IY.
+                compare_ci_ascii_loop(X, Y, IX, Res)
+            ;
+                ( CharRes = (<)
+                ; CharRes = (>)
+                ),
+                Res = CharRes
+            )
+        else
+            % X longer than Y.
+            Res = (>)
+        )
+    else if unsafe_index_next(Y, I, _IY, _CharY) then
+        % X shorter than Y.
+        Res = (<)
+    else
+        Res = (=)
+    ).
+
+%---------------------%
+
 prefix_length(P, S) = Index :-
     prefix_length_loop(P, S, 0, Index).
 
-- 
2.6.4



More information about the reviews mailing list