mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-17 06:47:17 +00:00
code_util.nl, float.nl, llds.nl, mercury_builtin.nl, opt_debug.nl, parser.nl, polymorphism.nl, sp_lib.nl, string.nl, string.nu.nl, type_util.nl, typecheck.nl, unify_gen.nl: Implement floating point. Makefile.common: Remove `-include test.dep' line. Use Mmake. int.nl: Update a few of the comments. io.nu.nl: For Sicstus Prolog, if main/2 is not defined then enter the debugger.
532 lines
17 KiB
Mathematica
532 lines
17 KiB
Mathematica
%-----------------------------------------------------------------------------%
|
|
|
|
:- module string.
|
|
% Beware that char_to_string/2 won't work with NU-Prolog 1.5.33 because
|
|
% of a NU-Prolog bug (fixed in 1.5.35).
|
|
|
|
% Main author: fjh.
|
|
|
|
% This modules provides basic string handling facilities.
|
|
|
|
% XXX The efficiency of many of these operations is very poor with
|
|
% the current implementation.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- interface.
|
|
:- import_module char, int, float.
|
|
|
|
:- pred string__length(string, int).
|
|
:- mode string__length(in, out) is det.
|
|
|
|
:- pred string__append(string, string, string).
|
|
:- mode string__append(in, in, out) is det.
|
|
:- mode string__append(in, in, in) is semidet. % implied
|
|
:- mode string__append(in, out, in) is semidet.
|
|
:- mode string__append(out, out, in) is nondet.
|
|
% Append two strings together.
|
|
%
|
|
% The following mode is semidet in the sense that it doesn't
|
|
% succeed more than once - but it does create a choice-point,
|
|
% which means it's inefficient and that the compiler can't deduce
|
|
% that it is semidet. Use string__remove_suffix instead.
|
|
% :- mode string__append(out, in, in) is semidet.
|
|
|
|
:- pred string__remove_suffix(string, string, string).
|
|
:- mode string__remove_suffix(in, in, out) is semidet.
|
|
% string__remove_suffix(String, Suffix, Prefix):
|
|
% The same as string__append(Prefix, Suffix, List) except that
|
|
% this is semidet whereas string__append(out, in, in) is nondet.
|
|
|
|
:- pred string__prefix(string, string).
|
|
:- mode string__prefix(in, in) is semidet.
|
|
:- mode string__prefix(in, out) is nondet.
|
|
% string__prefix(String, Prefix) is true iff Prefix is a
|
|
% prefix of String. Same as string__append(Prefix, _, String).
|
|
|
|
:- pred string__char_to_string(character, string).
|
|
:- mode string__char_to_string(in, out) is det.
|
|
:- mode string__char_to_string(out, in) is semidet.
|
|
% string__char_to_string(Char, String).
|
|
% Converts a character (single-character atom) to a string
|
|
% or vice versa.
|
|
|
|
:- pred string__int_to_string(int, string).
|
|
:- mode string__int_to_string(in, out) is det.
|
|
% Convert an integer to a string.
|
|
|
|
:- pred string__int_to_base_string(int, int, string).
|
|
:- mode string__int_to_base_string(in, in, out) is det.
|
|
% string__int_to_base_string(Int, Base, String):
|
|
% Convert an integer to a string in a given Base (between 2 and 36).
|
|
|
|
:- pred string__float_to_string(float, string).
|
|
:- mode string__float_to_string(in, out) is det.
|
|
% Convert an float to a string.
|
|
|
|
:- pred string__first_char(string, character, string).
|
|
:- mode string__first_char(in, in, in) is semidet. % implied
|
|
:- mode string__first_char(in, out, in) is semidet. % implied
|
|
:- mode string__first_char(in, in, out) is semidet. % implied
|
|
:- mode string__first_char(in, out, out) is semidet.
|
|
:- mode string__first_char(out, in, in) is det.
|
|
% string__first_char(String, Char, Rest) is true iff
|
|
% Char is the first character of String, and Rest is the
|
|
% remainder.
|
|
|
|
:- pred string__capitalize_first(string, string).
|
|
:- mode string__capitalize_first(in, out) is det.
|
|
% Convert the first character (if any) of a string to uppercase.
|
|
|
|
:- pred string__uncapitalize_first(string, string).
|
|
:- mode string__uncapitalize_first(in, out) is det.
|
|
% Convert the first character (if any) of a string to lowercase.
|
|
|
|
:- pred string__to_char_list(string, list(character)).
|
|
:- mode string__to_char_list(in, out) is det.
|
|
|
|
:- pred string__from_char_list(list(character), string).
|
|
:- mode string__from_char_list(in, out) is det.
|
|
|
|
:- pred string__to_int(string, int).
|
|
:- mode string__to_int(in, out) is semidet.
|
|
% Convert a string (of digits) to an int. If the string contains
|
|
% non-digit characters, string__to_int fails.
|
|
|
|
:- pred string__base_string_to_int(int, string, int).
|
|
:- mode string__base_string_to_int(in, in, out) is semidet.
|
|
% Convert a string of digits in the specified base (2-36) to an int.
|
|
% If the string contains invalid characters, the predicate fails.
|
|
|
|
:- pred string__to_float(string, float).
|
|
:- mode string__to_float(in, out) is semidet.
|
|
% Convert a string to an float. If the string is not
|
|
% a syntacatically correct float literal, string__to_float fails.
|
|
|
|
:- pred string__is_alpha(string).
|
|
:- mode string__is_alpha(in) is semidet.
|
|
% True if string contains only alphabetic characters (letters).
|
|
|
|
:- pred string__is_alpha_or_underscore(string).
|
|
:- mode string__is_alpha_or_underscore(in) is semidet.
|
|
% True if string contains only alphabetic characters and underscores.
|
|
|
|
:- pred string__is_alnum_or_underscore(string).
|
|
:- mode string__is_alnum_or_underscore(in) is semidet.
|
|
% True if string contains only letters, digits, and underscores.
|
|
|
|
:- pred string__pad_left(string, character, int, string).
|
|
:- mode string__pad_left(in, in, in, out) is det.
|
|
% string__pad_left(String0, PadChar, Width, String):
|
|
% insert `PadChar's at the left of `String0' until it is at least
|
|
% as long as `Width', giving `String'.
|
|
|
|
:- pred string__pad_right(string, character, int, string).
|
|
:- mode string__pad_right(in, in, in, out) is det.
|
|
% string__pad_right(String0, PadChar, Width, String):
|
|
% insert `PadChar's at the right of `String0' until it is at least
|
|
% as long as `Width', giving `String'.
|
|
|
|
:- pred string__duplicate_char(character, int, string).
|
|
:- mode string__duplicate_char(in, in, out) is det.
|
|
% string__duplicate_char(Char, Count, String):
|
|
% construct a string consisting of `Count' occurrences of `Char'
|
|
% in sequence.
|
|
|
|
:- pred string__index(string, int, character).
|
|
:- mode string__index(in, in, out) is semidet.
|
|
% string__index(String, Index, Char):
|
|
% `Char' is the (`Index' + 1)-th character of `String'.
|
|
% Fails if `Index' is out of range (negative, or greater than or
|
|
% equal to the length of `String').
|
|
|
|
:- pred string__index_det(string, int, character).
|
|
:- mode string__index_det(in, in, out) is det.
|
|
% string__index_det(String, Index, Char):
|
|
% `Char' is the (`Index' + 1)-th character of `String'.
|
|
% Calls error/1 if `Index' is out of range (negative, or greater than or
|
|
% equal to the length of `String').
|
|
|
|
:- pred string__split(string, int, string, string).
|
|
:- mode string__split(in, in, out, out) is det.
|
|
% string__split(String, Count, LeftSubstring, RightSubstring):
|
|
% `LeftSubstring' is the left-most `Count' characters of `String',
|
|
% and `RightSubstring' is the remainder of `String'.
|
|
% (If `Count' is out of the range [0, length of `String'], it is
|
|
% treated as if it were the nearest end-point of that range.)
|
|
|
|
:- pred string__left(string, int, string).
|
|
:- mode string__left(in, in, out) is det.
|
|
% string__left(String, Count, LeftSubstring):
|
|
% `LeftSubstring' is the left-most `Count' characters of `String'.
|
|
% (If `Count' is out of the range [0, length of `String'], it is
|
|
% treated as if it were the nearest end-point of that range.)
|
|
|
|
:- pred string__right(string, int, string).
|
|
:- mode string__right(in, in, out) is det.
|
|
% string__right(String, Count, RightSubstring):
|
|
% `RightSubstring' is what would remain of `String' if the
|
|
% left-most `Count' characters were removed.
|
|
% (If `Count' is out of the range [0, length of `String'], it is
|
|
% treated as if it were the nearest end-point of that range.)
|
|
|
|
:- pred string__substring(string, int, int, string).
|
|
:- mode string__substring(in, in, in, out) is det.
|
|
% string__substring(String, Start, Count, Substring):
|
|
% `Substring' is first the `Count' characters in what would
|
|
% remain of `String' after the first `Start' characters were
|
|
% removed.
|
|
% (If `Start' is out of the range [0, length of `String'], it is
|
|
% treated as if it were the nearest end-point of that range.
|
|
% If `Count' is out of the range [0, length of `String' - `Start'], it is
|
|
% treated as if it were the nearest end-point of that range.)
|
|
|
|
:- pred string__append_list(list(string), string).
|
|
:- mode string__append_list(in, out) is det.
|
|
:- mode string__append_list(out, in) is nondet.
|
|
% Append a list of strings together.
|
|
|
|
:- pred string__hash(string, int).
|
|
:- mode string__hash(in, out) is det.
|
|
% Compute a hash value for a string.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
:- import_module list, int, require.
|
|
|
|
:- pred string__to_int_list(string, list(int)).
|
|
:- mode string__to_int_list(in, out) is det.
|
|
:- mode string__to_int_list(out, in) is det.
|
|
:- mode string__to_int_list(in, in) is semidet. % implied
|
|
|
|
:- external(string__float_to_string/2).
|
|
:- external(string__to_float/2).
|
|
:- external(string__to_int_list/2).
|
|
|
|
string__to_int(String, Int) :-
|
|
string__base_string_to_int(10, String, Int).
|
|
|
|
string__base_string_to_int(Base, String, Int) :-
|
|
string__base_string_to_int_2(Base, String, 0, Int).
|
|
|
|
:- pred string__base_string_to_int_2(int, string, int, int).
|
|
:- mode string__base_string_to_int_2(in, in, in, out) is semidet.
|
|
|
|
string__base_string_to_int_2(Base, String, Int0, Int) :-
|
|
( string__first_char(String, Char, String1) ->
|
|
char__to_upper(Char, UpperChar),
|
|
string__digit_to_char(Digit, UpperChar),
|
|
Int1 is Base * Int0,
|
|
Int2 is Int1 + Digit,
|
|
string__base_string_to_int_2(Base, String1, Int2, Int)
|
|
;
|
|
Int = Int0
|
|
).
|
|
|
|
string__index(String, Int, Char) :-
|
|
string__to_int_list(String, CodeList),
|
|
list__index0(CodeList, Int, Code),
|
|
char_to_int(Char, Code).
|
|
|
|
string__index_det(String, Int, Char) :-
|
|
( string__index(String, Int, Char0) ->
|
|
Char = Char0
|
|
;
|
|
error("string__index_det: index out of range")
|
|
).
|
|
|
|
string__split(String, Count, LeftString, RightString) :-
|
|
(
|
|
Count < 0
|
|
->
|
|
LeftString = "",
|
|
RightString = String
|
|
;
|
|
string__to_int_list(String, CodesList),
|
|
list__split_list(Count, CodesList, LeftCodes, RightCodes)
|
|
->
|
|
string__to_int_list(LeftString, LeftCodes),
|
|
string__to_int_list(RightString, RightCodes)
|
|
;
|
|
LeftString = String,
|
|
RightString = ""
|
|
).
|
|
|
|
string__left(String, Count, LeftString) :-
|
|
string__split(String, Count, LeftString, _RightString).
|
|
|
|
string__right(String, RightCount, RightString) :-
|
|
string__length(String, Length),
|
|
LeftCount is Length - RightCount,
|
|
string__split(String, LeftCount, _LeftString, RightString).
|
|
|
|
string__substring(String, Start, Count, Substring) :-
|
|
string__right(String, Start, Right),
|
|
string__left(Right, Count, Substring).
|
|
|
|
string__length(String, Length) :-
|
|
string__to_int_list(String, List),
|
|
list__length(List, Length).
|
|
|
|
string__append(A, B, C) :-
|
|
string__to_int_list(A, LA),
|
|
string__to_int_list(B, LB),
|
|
string__to_int_list(C, LC),
|
|
list__append(LA, LB, LC).
|
|
|
|
string__remove_suffix(A, B, C) :-
|
|
string__to_int_list(A, LA),
|
|
string__to_int_list(B, LB),
|
|
string__to_int_list(C, LC),
|
|
list__remove_suffix(LA, LB, LC).
|
|
|
|
string__prefix(String, Prefix) :-
|
|
string__append(Prefix, _, String).
|
|
|
|
:- string__char_to_string(Char, String) when Char or String.
|
|
string__char_to_string(Char, String) :-
|
|
string__to_int_list(String, [Code]),
|
|
char_to_int(Char, Code).
|
|
|
|
string__int_to_string(N, Str) :-
|
|
string__int_to_base_string(N, 10, Str).
|
|
|
|
string__int_to_base_string(N, Base, Str) :-
|
|
(
|
|
Base >= 2, Base =< 36
|
|
->
|
|
true
|
|
;
|
|
error("string__int_to_base_string: invalid base")
|
|
),
|
|
string__int_to_base_string_1(N, Base, Str).
|
|
|
|
:- pred string__int_to_base_string_1(int, int, string).
|
|
:- mode string__int_to_base_string_1(in, in, out) is det.
|
|
|
|
string__int_to_base_string_1(N, Base, Str) :-
|
|
(
|
|
N < 0
|
|
->
|
|
N1 is 0 - N,
|
|
string__int_to_base_string_2(N1, Base, Str1),
|
|
string__append("-", Str1, Str)
|
|
;
|
|
string__int_to_base_string_2(N, Base, Str)
|
|
).
|
|
|
|
:- pred string__int_to_base_string_2(int, int, string).
|
|
:- mode string__int_to_base_string_2(in, in, out) is det.
|
|
|
|
string__int_to_base_string_2(N, Base, Str) :-
|
|
(
|
|
N < Base
|
|
->
|
|
string__digit_to_char_det(N, DigitChar),
|
|
string__char_to_string(DigitChar, Str)
|
|
;
|
|
N10 is N mod Base,
|
|
N1 is N // Base,
|
|
string__digit_to_char_det(N10, DigitChar),
|
|
string__char_to_string(DigitChar, DigitString),
|
|
string__int_to_base_string_2(N1, Base, Str1),
|
|
string__append(Str1, DigitString, Str)
|
|
).
|
|
|
|
:- pred string__digit_to_char_det(int, character).
|
|
:- mode string__digit_to_char_det(in, out) is det.
|
|
|
|
string__digit_to_char_det(Digit, Char) :-
|
|
( string__digit_to_char(Digit, Char0) ->
|
|
Char = Char0
|
|
;
|
|
error("string__digit_to_char failed")
|
|
).
|
|
|
|
% Simple-minded, but extremely portable.
|
|
|
|
:- pred string__digit_to_char(int, character).
|
|
:- mode string__digit_to_char(in, out) is semidet.
|
|
:- mode string__digit_to_char(out, in) is semidet.
|
|
|
|
string__digit_to_char(0, '0').
|
|
string__digit_to_char(1, '1').
|
|
string__digit_to_char(2, '2').
|
|
string__digit_to_char(3, '3').
|
|
string__digit_to_char(4, '4').
|
|
string__digit_to_char(5, '5').
|
|
string__digit_to_char(6, '6').
|
|
string__digit_to_char(7, '7').
|
|
string__digit_to_char(8, '8').
|
|
string__digit_to_char(9, '9').
|
|
string__digit_to_char(10, 'A').
|
|
string__digit_to_char(11, 'B').
|
|
string__digit_to_char(12, 'C').
|
|
string__digit_to_char(13, 'D').
|
|
string__digit_to_char(14, 'E').
|
|
string__digit_to_char(15, 'F').
|
|
string__digit_to_char(16, 'G').
|
|
string__digit_to_char(17, 'H').
|
|
string__digit_to_char(18, 'I').
|
|
string__digit_to_char(19, 'J').
|
|
string__digit_to_char(20, 'K').
|
|
string__digit_to_char(21, 'L').
|
|
string__digit_to_char(22, 'M').
|
|
string__digit_to_char(23, 'N').
|
|
string__digit_to_char(24, 'O').
|
|
string__digit_to_char(25, 'P').
|
|
string__digit_to_char(26, 'Q').
|
|
string__digit_to_char(27, 'R').
|
|
string__digit_to_char(28, 'S').
|
|
string__digit_to_char(29, 'T').
|
|
string__digit_to_char(30, 'U').
|
|
string__digit_to_char(31, 'V').
|
|
string__digit_to_char(32, 'W').
|
|
string__digit_to_char(33, 'X').
|
|
string__digit_to_char(34, 'Y').
|
|
string__digit_to_char(35, 'Z').
|
|
|
|
string__first_char(String0, Char, String) :-
|
|
string__to_int_list(String0, List0),
|
|
List0 = [CharCode | List],
|
|
string__to_int_list(String, List),
|
|
char_to_int(Char, CharCode).
|
|
|
|
string__to_char_list(String, CharList) :-
|
|
string__to_int_list(String, IntList),
|
|
string__int_list_to_char_list(IntList, CharList).
|
|
|
|
string__from_char_list(CharList, String) :-
|
|
string__char_list_to_int_list(CharList, IntList),
|
|
string__to_int_list(String, IntList).
|
|
|
|
:- pred string__int_list_to_char_list(list(int), list(character)).
|
|
:- mode string__int_list_to_char_list(in, out) is det.
|
|
|
|
string__int_list_to_char_list([], []).
|
|
string__int_list_to_char_list([Code | Codes], [Char | Chars]) :-
|
|
( char_to_int(Char0, Code) ->
|
|
Char = Char0
|
|
;
|
|
error("string__int_list_to_char_list: char_to_int failed")
|
|
),
|
|
string__int_list_to_char_list(Codes, Chars).
|
|
|
|
:- pred string__char_list_to_int_list(list(character), list(int)).
|
|
:- mode string__char_list_to_int_list(in, out) is det.
|
|
|
|
string__char_list_to_int_list([], []).
|
|
string__char_list_to_int_list([Char | Chars], [Code | Codes]) :-
|
|
( char_to_int(Char, Code0) ->
|
|
Code = Code0
|
|
;
|
|
error("string__char_list_to_int_list: char_to_int failed")
|
|
),
|
|
string__char_list_to_int_list(Chars, Codes).
|
|
|
|
string__capitalize_first(S0, S) :-
|
|
( string__first_char(S0, C, S1) ->
|
|
char__to_upper(C, UpperC),
|
|
string__first_char(S, UpperC, S1)
|
|
;
|
|
S = S0
|
|
).
|
|
|
|
string__uncapitalize_first(S0, S) :-
|
|
( string__first_char(S0, C, S1) ->
|
|
char__to_lower(C, LowerC),
|
|
string__first_char(S, LowerC, S1)
|
|
;
|
|
S = S0
|
|
).
|
|
|
|
string__is_alpha(S) :-
|
|
( string__first_char(S, C, S1) ->
|
|
char__is_alpha(C),
|
|
string__is_alpha(S1)
|
|
;
|
|
true
|
|
).
|
|
|
|
string__is_alpha_or_underscore(S) :-
|
|
( string__first_char(S, C, S1) ->
|
|
char__is_alpha_or_underscore(C),
|
|
string__is_alpha_or_underscore(S1)
|
|
;
|
|
true
|
|
).
|
|
|
|
string__is_alnum_or_underscore(S) :-
|
|
( string__first_char(S, C, S1) ->
|
|
char__is_alnum_or_underscore(C),
|
|
string__is_alnum_or_underscore(S1)
|
|
;
|
|
true
|
|
).
|
|
|
|
string__pad_left(String0, PadChar, Width, String) :-
|
|
string__length(String0, Length),
|
|
( Length < Width ->
|
|
Count is Width - Length,
|
|
string__duplicate_char(PadChar, Count, PadString),
|
|
string__append(PadString, String0, String)
|
|
;
|
|
String = String0
|
|
).
|
|
|
|
string__pad_right(String0, PadChar, Width, String) :-
|
|
string__length(String0, Length),
|
|
( Length < Width ->
|
|
Count is Width - Length,
|
|
string__duplicate_char(PadChar, Count, PadString),
|
|
string__append(String0, PadString, String)
|
|
;
|
|
String = String0
|
|
).
|
|
|
|
string__duplicate_char(Char, Count, String) :-
|
|
( Count = 0 ->
|
|
String = ""
|
|
;
|
|
Count1 is Count - 1,
|
|
string__first_char(String, Char, String1),
|
|
string__duplicate_char(Char, Count1, String1)
|
|
).
|
|
|
|
string__append_list([], "").
|
|
string__append_list([S | Ss], L) :-
|
|
string__append_list(Ss, L0),
|
|
string__append(S, L0, L).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% Note - string__hash is also defined in code/imp.h
|
|
% The two definitions must be kept identical.
|
|
|
|
string__hash(String, HashVal) :-
|
|
string__length(String, Length),
|
|
string__to_int_list(String, CodeList),
|
|
string__hash_2(CodeList, 0, HashVal0),
|
|
HashVal is HashVal0 ^ Length.
|
|
|
|
:- pred string__hash_2(list(int), int, int).
|
|
:- mode string__hash_2(in, in, out) is det.
|
|
|
|
string__hash_2([], HashVal, HashVal).
|
|
string__hash_2([X | Xs], HashVal0, HashVal) :-
|
|
string__combine_hash(HashVal0, X, HashVal1),
|
|
string__hash_2(Xs, HashVal1, HashVal).
|
|
|
|
:- pred string__combine_hash(int, int, int).
|
|
:- mode string__combine_hash(in, in, out) is det.
|
|
|
|
string__combine_hash(H0, X, H) :-
|
|
H1 is H0 << 5,
|
|
H2 is H1 ^ H0,
|
|
H is H2 ^ X.
|
|
|
|
:- end_module string.
|
|
|
|
%-----------------------------------------------------------------------------%
|