Skip to content

Commit

Permalink
Merge pull request #9533 from bschommer/string-suffix-prefix
Browse files Browse the repository at this point in the history
String suffix and prefix functions.
  • Loading branch information
nojb committed Jun 24, 2020
2 parents 244298a + ddb1b5e commit 34dbc54
Show file tree
Hide file tree
Showing 6 changed files with 53 additions and 4 deletions.
4 changes: 4 additions & 0 deletions Changes
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,10 @@ Working version
and more generally all other data that is not a well-formed OCaml value
(Xavier Leroy, review by Damien Doligez and Gabriel Scherer)

- #9533: Added String.starts_with and String.ends_with.
(Bernhard Schommer, review by Daniel Bünzli, Gabriel Scherer and
Alain Frisch)

### Other libraries:

* #9206, #9419: update documentation of the threads library;
Expand Down
4 changes: 1 addition & 3 deletions stdlib/filename.ml
Original file line number Diff line number Diff line change
Expand Up @@ -100,9 +100,7 @@ module Unix : SYSDEPS = struct
&& (String.length n < 2 || String.sub n 0 2 <> "./")
&& (String.length n < 3 || String.sub n 0 3 <> "../")
let check_suffix name suff =
String.length name >= String.length suff &&
String.sub name (String.length name - String.length suff)
(String.length suff) = suff
String.ends_with ~suffix:suff name

let chop_suffix_opt ~suffix filename =
let len_s = String.length suffix and len_f = String.length filename in
Expand Down
19 changes: 19 additions & 0 deletions stdlib/string.ml
Original file line number Diff line number Diff line change
Expand Up @@ -231,3 +231,22 @@ let to_seq s = bos s |> B.to_seq
let to_seqi s = bos s |> B.to_seqi

let of_seq g = B.of_seq g |> bts

let starts_with ~prefix s =
let len_s = length s
and len_pre = length prefix in
let rec aux i =
if i = len_pre then true
else if unsafe_get s i <> unsafe_get prefix i then false
else aux (i + 1)
in len_s >= len_pre && aux 0

let ends_with ~suffix s =
let len_s = length s
and len_suf = length suffix in
let diff = len_s - len_suf in
let rec aux i =
if i = len_suf then true
else if unsafe_get s (diff + i) <> unsafe_get suffix i then false
else aux (i + 1)
in diff >= 0 && aux 0
8 changes: 8 additions & 0 deletions stdlib/string.mli
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,14 @@ val equal: t -> t -> bool
(** The equal function for strings.
@since 4.03.0 *)

val starts_with : prefix:t -> t -> bool
(** [String.starts_with prefix s] tests if [s] starts with [prefix]
@since 4.12.0 *)

val ends_with : suffix:t -> t -> bool
(** [String.ends_with suffix s] tests if [s] ends with [suffix]
@since 4.12.0 *)

val split_on_char: char -> string -> string list
(** [String.split_on_char sep s] returns the list of all (possibly empty)
substrings of [s] that are delimited by the [sep] character.
Expand Down
8 changes: 8 additions & 0 deletions stdlib/stringLabels.mli
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,14 @@ val equal: t -> t -> bool
(** The equal function for strings.
@since 4.05.0 *)

val starts_with : prefix:t -> t -> bool
(** [String.starts_with prefix s] tests if [s] starts with [prefix]
@since 4.12.0 *)

val ends_with : suffix:t -> t -> bool
(** [String.ends_with suffix s] tests if [s] ends with [suffix]
@since 4.12.0 *)

val split_on_char: sep:char -> string -> string list
(** [String.split_on_char sep s] returns the list of all (possibly empty)
substrings of [s] that are delimited by the [sep] character.
Expand Down
14 changes: 13 additions & 1 deletion testsuite/tests/lib-string/test_string.ml
Original file line number Diff line number Diff line change
Expand Up @@ -51,5 +51,17 @@ let () =
while !sz >= 0 do push big l; sz += Sys.max_string_length done;
while !sz <= 0 do push big l; sz += Sys.max_string_length done;
try ignore (String.concat "" !l); assert false
with Invalid_argument _ -> ()
with Invalid_argument _ -> ();
assert(String.starts_with ~prefix:"foob" "foobarbaz");
assert(String.starts_with ~prefix:"" "foobarbaz");
assert(String.starts_with ~prefix:"" "");
assert(not (String.starts_with ~prefix:"foobar" "bar"));
assert(not (String.starts_with ~prefix:"foo" ""));
assert(not (String.starts_with ~prefix:"fool" "foobar"));
assert(String.ends_with ~suffix:"baz" "foobarbaz");
assert(String.ends_with ~suffix:"" "foobarbaz");
assert(String.ends_with ~suffix:"" "");
assert(not (String.ends_with ~suffix:"foobar" "bar"));
assert(not (String.ends_with ~suffix:"foo" ""));
assert(not (String.ends_with ~suffix:"obaz" "foobar"));
end

0 comments on commit 34dbc54

Please sign in to comment.