(* * ExtString - Additional functions for string manipulations. * Copyright (C) 2003 Nicolas Cannasse * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version, * with the special exception on linking described in file LICENSE. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *) exception Invalid_string module String = struct include String let init len f = let s = create len in for i = 0 to len - 1 do unsafe_set s i (f i) done; s let starts_with str p = let len = length p in if length str < len then false else sub str 0 len = p let ends_with s e = let el = length e in let sl = length s in if sl < el then false else sub s (sl-el) el = e let find str sub = let sublen = length sub in if sublen = 0 then 0 else let found = ref 0 in let len = length str in try for i = 0 to len - sublen do let j = ref 0 in while unsafe_get str (i + !j) = unsafe_get sub !j do incr j; if !j = sublen then begin found := i; raise Exit; end; done; done; raise Invalid_string with Exit -> !found let exists str sub = try ignore(find str sub); true with Invalid_string -> false let strip ?(chars=" \t\r\n") s = let p = ref 0 in let l = length s in while !p < l && contains chars (unsafe_get s !p) do incr p; done; let p = !p in let l = ref (l - 1) in while !l >= p && contains chars (unsafe_get s !l) do decr l; done; sub s p (!l - p + 1) let split str sep = let p = find str sep in let len = length sep in let slen = length str in sub str 0 p, sub str (p + len) (slen - p - len) let rec nsplit str sep = try let s1 , s2 = split str sep in s1 :: nsplit s2 sep with Invalid_string -> [str] let join = concat let slice ?(first=0) ?(last=Sys.max_string_length) s = let clip _min _max x = max _min (min _max x) in let i = clip 0 (length s) (if (first<0) then (length s) + first else first) and j = clip 0 (length s) (if (last<0) then (length s) + last else last) in if i>=j || i=length s then create 0 else sub s i (j-i) let lchop s = if s = "" then "" else sub s 1 (length s - 1) let rchop s = if s = "" then "" else sub s 0 (length s - 1) let of_int = string_of_int let of_float = string_of_float let of_char = make 1 let to_int s = try int_of_string s with _ -> raise Invalid_string let to_float s = try float_of_string s with _ -> raise Invalid_string let map f s = let len = length s in let sc = create len in for i = 0 to len - 1 do unsafe_set sc i (f (unsafe_get s i)) done; sc (* fold_left and fold_right by Eric C. Cooper *) let fold_left f init str = let n = String.length str in let rec loop i result = if i = n then result else loop (i + 1) (f result str.[i]) in loop 0 init let fold_right f str init = let n = String.length str in let rec loop i result = if i = 0 then result else let i' = i - 1 in loop i' (f str.[i'] result) in loop n init (* explode and implode from the OCaml Expert FAQ. *) let explode s = let rec exp i l = if i < 0 then l else exp (i - 1) (s.[i] :: l) in exp (String.length s - 1) [] let implode l = let res = String.create (List.length l) in let rec imp i = function | [] -> res | c :: l -> res.[i] <- c; imp (i + 1) l in imp 0 l let replace_chars f s = let len = String.length s in let tlen = ref 0 in let rec loop i acc = if i = len then acc else let s = f (unsafe_get s i) in tlen := !tlen + length s; loop (i+1) (s :: acc) in let strs = loop 0 [] in let sbuf = create !tlen in let pos = ref !tlen in let rec loop2 = function | [] -> () | s :: acc -> let len = length s in pos := !pos - len; blit s 0 sbuf !pos len; loop2 acc in loop2 strs; sbuf let replace ~str ~sub ~by = try let i = find str sub in (true, (slice ~last:i str) ^ by ^ (slice ~first:(i+(String.length sub)) str)) with Invalid_string -> (false, String.copy str) let lazy_concat s1 s2 = lazy ((Lazy.force s1) ^ (Lazy.force s2)) end