String Operations


These are three functions to operate on strings.

extract :string # int # int -> string

extracts a substring from a string: the first argument is the source string, the second argument is the starting position of the substring in the string (the first character in a string is at position 1), and the third argument is the length of the substring. It fails with string "extract" if the numeric arguments are out of range.

match :string # string -> bool

returns true if the first argument is equal to the second argument, the latter can contain special characters: ? is about to any character; * refers to any string of characters; # refers to any numeric character; @ refers to any alphabetic character.

StrLessThan :string # string -> bool

returns true if the first argument is equal to or less than the second one (in the lexicographical order), false otherwise.


let extract:= 
    fun(x:string, f:int, L:int):string is
      use s:= explode(x)
      ext l:= count(s)
      in if l < f Or l < f + L - 1 
           then failwith "extract"
           else use r:= var {nth(s,f)}
                and c:= var 1
                in if L = 1 
                     then implode(at r)
                      else (while (at c) <= L - 1 do 
                              (r<- nth(s, (at c) + f) :: (at r);
                               c <- (at c) + 1 ); 
                            implode(reverse(at r)) 
                           ); 

let match := fun(a: string, b:string):bool is
     use letters:= explode("qwertyuiopasdfghjklzxcvbnm") append
                   explode("QWERTYUIOPASDFGHJKLZXCVBNM") 
     and  digits:= explode("1234567890")
     ext rec try:= fun(a :seq string, b :seq string):bool is
               if emptyseq(a) 
                 then emptyseq(b)
                 else 
                   if first(a) = "*" 
                     then subsL(rest(a),b)
                     else 
                       if emptyseq(b) 
                         then false
                         else 
                           if first(a) = "#" 
                             then 
                               if first(b) isin digits 
                                 then try(rest(a),rest(b))
                                 else false
                             else 
                               if first(a) = "@" 
                                 then 
                                   if first(b) isin letters 
                                     then try(rest(a),rest(b))
                                     else false
                                 else 
                                   if (first(a) = "?") Or (first(a) = first(b)) 
                                     then try(rest(a),rest(b))
                                     else false
     and subsL:= fun(a :seq string, b :seq string): bool is
           if try(a,b) 
             then true
             else 
               if Not emptyseq(b) 
                 then subsL(a, rest(b)) 
                 else false
     in try(explode(b),  explode(a));

let StrLessThan:= fun(x:string, y:string):bool is
   use rec lessThanAscii:= fun(x:seq int, y:seq int):bool is
           if emptyseq(x) then true
           else if emptyseq(y) then false
           else if first(x) = first(y)
                then lessThanAscii(rest(x), rest(y))
                else if first(x)  first(y)
                     then true
                     else false
   in lessThanAscii(explodeascii(x), explodeascii(y));