From f8bb365c94a94135a87a9525aba7a40cca28499e Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Tue, 5 Apr 2016 14:38:49 +0200 Subject: [PATCH] implement `CCString.{drop,take,chop_prefix,chop_suffix,filter,filter_map}` --- src/core/CCString.cppo.ml | 37 ++++++++++++++++++++++++ src/core/CCString.mli | 59 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+) diff --git a/src/core/CCString.cppo.ml b/src/core/CCString.cppo.ml index 155892eb..b476f92f 100644 --- a/src/core/CCString.cppo.ml +++ b/src/core/CCString.cppo.ml @@ -424,6 +424,27 @@ let suffix ~suf s = !i = String.length suf ) +let take n s = + if n < String.length s + then String.sub s 0 n + else s + +let drop n s = + if n < String.length s + then String.sub s n (String.length s - n) + else "" + +let take_drop n s = take n s, drop n s + +let chop_suffix ~suf s = + if suffix ~suf s + then Some (String.sub s 0 (String.length s-String.length suf)) + else None + +let chop_prefix ~pre s = + if prefix ~pre s + then Some (String.sub s (String.length pre) (String.length s-String.length pre)) + else None let blit = String.blit @@ -547,6 +568,22 @@ let mapi f s = init (length s) (fun i -> f i s.[i]) #endif +let filter_map f s = + let buf = Buffer.create (String.length s) in + iter + (fun c -> match f c with + | None -> () + | Some c' -> Buffer.add_char buf c') + s; + Buffer.contents buf + +let filter f s = + let buf = Buffer.create (String.length s) in + iter + (fun c -> if f c then Buffer.add_char buf c) + s; + Buffer.contents buf + let flat_map ?sep f s = let buf = Buffer.create (String.length s) in iteri diff --git a/src/core/CCString.mli b/src/core/CCString.mli index 6720bf1c..9cf809ba 100644 --- a/src/core/CCString.mli +++ b/src/core/CCString.mli @@ -219,6 +219,46 @@ val suffix : suf:string -> string -> bool not (suffix ~suf:"abcd" "cd") *) +val chop_prefix : pre:string -> string -> string option +(** [chop_pref ~pre s] removes [pre] from [s] if [pre] really is a prefix + of [s], returns [None] otherwise + @since NEXT_RELEASE *) + +(*$= & ~printer:Q.Print.(option string) + (Some "cd") (chop_prefix ~pre:"aab" "aabcd") + None (chop_prefix ~pre:"ab" "aabcd") + None (chop_prefix ~pre:"abcd" "abc") +*) + +val chop_suffix : suf:string -> string -> string option +(** [chop_suffix ~suf s] removes [suf] from [s] if [suf] really is a suffix + of [s], returns [None] otherwise + @since NEXT_RELEASE *) + +(*$= & ~printer:Q.Print.(option string) + (Some "ab") (chop_suffix ~suf:"cd" "abcd") + None (chop_suffix ~suf:"cd" "abcde") + None (chop_suffix ~suf:"abcd" "cd") +*) + +val take : int -> string -> string +(** [take n s] keeps only the [n] first chars of [s] + @since NEXT_RELEASE *) + +val drop : int -> string -> string +(** [drop n s] removes the [n] first chars of [s] + @since NEXT_RELEASE *) + +val take_drop : int -> string -> string * string +(** [take_drop n s = take n s, drop n s] + @since NEXT_RELEASE *) + +(*$= + ("ab", "cd") (take_drop 2 "abcd") + ("abc", "") (take_drop 3 "abc") + ("abc", "") (take_drop 5 "abc") +*) + val lines : string -> string list (** [lines s] returns a list of the lines of [s] (splits along '\n') @since 0.10 *) @@ -272,6 +312,25 @@ val mapi : (int -> char -> char) -> string -> string (** Map chars with their index @since 0.12 *) +val filter_map : (char -> char option) -> string -> string +(** @since NEXT_RELEASE *) + +(*$= & ~printer:Q.Print.string + "bcef" (filter_map \ + (function 'c' -> None | c -> Some (Char.chr (Char.code c + 1))) "abcde") +*) + +val filter : (char -> bool) -> string -> string +(** @since NEXT_RELEASE *) + +(*$= & ~printer:Q.Print.string + "abde" (filter (function 'c' -> false | _ -> true) "abcdec") +*) + +(*$Q + Q.printable_string (fun s -> filter (fun _ -> true) s = s) +*) + val flat_map : ?sep:string -> (char -> string) -> string -> string (** Map each chars to a string, then concatenates them all @param sep optional separator between each generated string