2:- module(pstring, [
    3        
    4    pchar/1,
    5    pchar_upper/2,
    6    pchar_lower/2,
    7    pchar_type/2,
    8    pchar_code/2,
    9
   10    % String Library
   11    pstr_empty/1,
   12    pstr_upper/2,
   13    pstr_lower/2,
   14    pstr_split/3,
   15    pstr_join/3,
   16    pstr_contains/2,
   17    pstr_contains/3,
   18    pstr_prefix/2,
   19    pstr_prefix/3,
   20    pstr_trim/2,
   21    pstr_replace/4
   22]).   23
   24:- use_module(purity).   25:- use_module(pchar).   26
   27:- multifile purity:pcompare/4.   28
   29purity:pcompare(pstring, A, B, C) :- pcompare(plist(pchar), A, B, C).
   30purity:pcompare(pchar, A, B, C) :- ch(A, B, C). 
   31
   32
   33% pstr_empty(Str).
   34%
   35% Str is an empty string
   36%
   37pstr_empty([]).
   38
   39
   40% pstr_upper(String, Upper).
   41%
   42% Upper is the upper case version of String
   43%
   44% C = the first character of String
   45% T = the tail of Sting
   46% U = the upper case version of C
   47% R = the tail of Upper
   48%
   49pstr_upper([], []).
   50pstr_upper([C|T], [U|R]) :-
   51        ch_map(C, _, U),
   52        pstr_upper(T, R).
   53
   54
   55% pstr_lower(String, Lower).
   56%
   57% Lower is the lower case version of String
   58%
   59% C = the first character of String
   60% T = the tail of Sting
   61% U = the lower case version of C
   62% R = the tail of Lower
   63%
   64pstr_lower([], []).
   65pstr_lower([C|T], [L|R]) :-
   66        ch_map(C, L, _),
   67        pstr_lower(T, R).
   68
   69
   70% pstr_replace(String, Find, Replace, Replaced).
   71%
   72% Replaced is String with the first instance of Find changed to Replace
   73%
   74% A = the first character of String
   75% T = the tail of String
   76% F = Find
   77% R = Replace
   78% Rp = Replaced
   79% Rpt = the tail of Replaced
   80% Orig = String or part of String
   81% 
   82pstr_replace([], _, _, []).
   83pstr_replace([A|T], F, R, Rp) :-
   84        pstr_prefix(F, [A|T], IsPrefix),
   85        pstr_replace_(IsPrefix, [A|T], F, R, Rp).
   86
   87pstr_replace_(true, Orig, F, R, Rp) :-
   88        append(F, Remaining, Orig),
   89        append(R, Remaining, Rp).
   90pstr_replace_(false, [A|T], F, R, [A|Rpt]) :-
   91        pstr_replace(T, F, R, Rpt).
   92
   93
   94% pstr_trim(UnTrimmed, Trimmed).
   95%
   96% Trimmed is UnTrimmed with all whitespace removed from the start and end
   97%
   98% A = the first character of UnTrimmed
   99% T = the tail of UnTrimmed
  100% Out = Trimmed
  101% R = true of false based on whether the end of UnTrimmed is all whitespace or not
  102%
  103pstr_trim([A|T], Out) :-
  104        pchar_type(A, Type),
  105        pstr_trim_start(Type, A, T, Out).
  106
  107pstr_trim_start(whitespace, _, T, Out) :-  pstr_trim(T, Out).
  108pstr_trim_start(alpha, A, T, [A|Out]) :- pstr_trim_end(T, Out).
  109pstr_trim_start(digit, A, T, [A|Out]) :- pstr_trim_end(T, Out).
  110pstr_trim_start(symbol, A, T, [A|Out]) :- pstr_trim_end(T, Out).
  111
  112pstr_trim_end([], []).
  113pstr_trim_end([A|T], Trimmed) :-
  114        pstr_all_whitespace([A|T], R),
  115        pstr_trim_end_(R, A, T, Trimmed).
  116
  117pstr_trim_end_(true, _, _, []).
  118pstr_trim_end_(false, A, T, [A|End]) :- pstr_trim_end(T, End).
  119
  120pstr_all_whitespace([], true).
  121pstr_all_whitespace([A|T], R) :-
  122        pchar_type(A, Type),
  123        pstr_all_whitespace_(Type, T, R).
  124
  125pstr_all_whitespace_(whitespace, T, R) :- pstr_all_whitespace(T, R).
  126pstr_all_whitespace_(alpha, _, false).
  127pstr_all_whitespace_(digit, _, false).
  128pstr_all_whitespace_(symbol, _, false).
  129
  130% pstr_split(StrToSplit, DelimiterChar, Split).
  131% 
  132% Split is StrToSplit separated by DelimiterChar into lists. 
  133% DelimiterChar is not included in Split.
  134%
  135pstr_split(A, D, B) :-
  136        pchar(D),
  137        pstr_split_(A, D, B).
  138
  139pstr_split_([], _, []).
  140pstr_split_([A|T], D, Split) :-
  141        pdif_char(A,D,B),
  142        pstr_split(B,A,T,D,Split).
  143
  144pstr_split(false, D, T, D, Split) :-
  145        pstr_split_(T,D,Split).
  146pstr_split(true, A, T, D, [S|Rest]) :-
  147        find_split([A|T], D, Rem, S),
  148        pstr_split_(Rem, D, Rest). 
  149
  150find_split([], _, [], []).
  151find_split([A|T], D, Rem, Split) :-
  152        pdif_char(A,D,B),
  153        find_split(B, A, T, D, Rem, Split).
  154
  155find_split(false, D, T, D, T, []).
  156find_split(true, A, T, D, Rem, [A|Rest]) :-
  157        find_split(T, D, Rem, Rest).
  158
  159
  160
  161% pstr_join(ListOfStrings, Delimiter, Joined).
  162%
  163% Joined is ListOfStrings flattened into a single list and separated by Delimiter
  164%
  165pstr_join(A, D, B) :-
  166        pchar(D),
  167        pstr_join_(A, D, B).
  168
  169pstr_join_([], _, []).
  170pstr_join_([A|T], D, S) :-
  171        pstr_join(A, T, D, S).
  172
  173pstr_join([], T, D, R) :-
  174        pstr_join2(T, D, R).
  175pstr_join([A|At], T, D, [A|R]) :-
  176        pstr_join(At, T, D, R).
  177
  178pstr_join2([], _, []).
  179pstr_join2([N|T], D, [D|R]) :-
  180        pstr_join_([N|T], D, R).
  181
  182
  183% pstr_contains(String, SubString).
  184%
  185% Holds if SubString is a sequence within String
  186%
  187pstr_contains(String, SubString) :-
  188         pstr_contains(String, SubString, true).
  189
  190% pstr_contains(String, SubString, Contains).
  191% 
  192% Contains is true if SubString is a sequence within String, otherwise false
  193%
  194pstr_contains([], _, false). 
  195pstr_contains([A|T], B, C) :-
  196        pstr_prefix(B, [A|T], Prefix),
  197        pstr_contains_(Prefix, [A|T], B, C).
  198
  199pstr_contains_(true, _, _, true).
  200pstr_contains_(false, [_|At], B, C) :-
  201        pstr_contains(At, B, C).
  202
  203
  204% pstr_prefix(Prefix, String).
  205%
  206% Holds if Prefix is the starting sequence of String
  207%
  208pstr_prefix(Prefix, String) :-
  209        pstr_prefix(Prefix, String, true).
  210
  211% pstr_prefix(Prefix, String, IsPrefix).
  212%
  213% IsPrefix is true if Prefix is the starting sequence of String
  214%
  215pstr_prefix([], _, true).
  216pstr_prefix([A|At], [B|Bt], IsPrefix) :-
  217        ch(A, B, C),
  218        pstr_prefix(C, At, Bt, IsPrefix).
  219
  220pstr_prefix(=, At, Bt, B) :- 
  221        pstr_prefix(At, Bt, B).
  222pstr_prefix(<, _, _, false).
  223pstr_prefix(>, _, _, false)