diff --git a/src/core/CCString.cppo.ml b/src/core/CCString.cppo.ml index 7fd6e70e..4a176eb9 100644 --- a/src/core/CCString.cppo.ml +++ b/src/core/CCString.cppo.ml @@ -116,6 +116,39 @@ let rfind ~sub s = with Exit -> !i +(* replace substring [s.[pos]....s.[pos+len-1]] by [by] in [s] *) +let replace_at_ ~pos ~len ~by s = + let b = Buffer.create (length s + length by - len) in + Buffer.add_substring b s 0 pos; + Buffer.add_string b by; + Buffer.add_substring b s (pos+len) (String.length s - pos - len); + Buffer.contents b + +let replace ?(which=`All) ~sub ~by s = match which with + | `Left -> + let i = find ~sub s in + if i>=0 then replace_at_ ~pos:i ~len:(String.length sub) ~by s else s + | `Right -> + let i = rfind ~sub s in + if i>=0 then replace_at_ ~pos:i ~len:(String.length sub) ~by s else s + | `All -> + let b = Buffer.create (String.length s) in + let start = ref 0 in + while !start < String.length s do + let i = find ~start:!start ~sub s in + if i>=0 then ( + (* between last and cur occurrences *) + Buffer.add_substring b s !start (i- !start); + Buffer.add_string b by; + start := i + String.length sub + ) else ( + (* add remainder *) + Buffer.add_substring b s !start (String.length s - !start); + start := String.length s (* stop *) + ) + done; + Buffer.contents b + module Split = struct type split_state = | SplitStop diff --git a/src/core/CCString.mli b/src/core/CCString.mli index e6b86ff1..4e00f8a0 100644 --- a/src/core/CCString.mli +++ b/src/core/CCString.mli @@ -129,6 +129,24 @@ val rfind : sub:string -> string -> int rfind ~sub:"bc" "abcdbcd" = 4 *) +val replace : ?which:[`Left|`Right|`All] -> sub:string -> by:string -> string -> string +(** [replace ~sub ~by s] replaces some occurrences of [sub] by [by] in [s] + @param which decides whether the occurrences to replace are: + {ul + {il [`Left] first occurrence from the left (beginning)} + {il [`Right] first occurrence from the right (end)} + {il [`All] all occurrences (default)} + } + @since NEXT_RELEASE *) + +(*$= & ~printer:CCFun.id + (replace ~which:`All ~sub:"a" ~by:"b" "abcdabcd") "bbcdbbcd" + (replace ~which:`Left ~sub:"a" ~by:"b" "abcdabcd") "bbcdabcd" + (replace ~which:`Right ~sub:"a" ~by:"b" "abcdabcd") "abcdbbcd" + (replace ~which:`All ~sub:"ab" ~by:"hello" " abab cdabb a") \ + " hellohello cdhellob a" +*) + val is_sub : sub:string -> int -> string -> int -> len:int -> bool (** [is_sub ~sub i s j ~len] returns [true] iff the substring of [sub] starting at position [i] and of length [len] *)