ocaml/ocaml — pull request #13 by dbuenzli (2014-02-16 13:24:49+00:00)
Title: Add String.{cut,rcut}.

As a follow up to pull request https://github.com/ocaml/ocaml/pull/10. This pull request adds `String.{cut,rcut}` which cuts a string in two at a given non empty separator `sep` starting either from the beginning of the string or from the end. The signature for `StringLabels` is :
```
val cut : ~sep:string -> string -> (string * string) option
val rcut : ~sep:string -> string -> (string * string) option
```
These functions have the following invariants. First for any non empty `sep` and `s` such that `sep` is in `s` we have:
```
assert (String.{cut,rcut} sep s = Some (l,r))
assert (l ^ sep ^ r = s)
```
Then for any `s` such that `sep` doesn't occur in `s`:
```
assert (String.{rcut,cut} sep s = None)
```
Here is the result of `String.{cut,rcut}` on a few edge cases.
```
(* String.cut *)
assert (try ignore (String.cut "" ""); false with Invalid_argument _ -> true);
assert (try ignore (String.cut "" "123"); false with Invalid_argument _ -> true);
assert (String.cut "," "" = None);
assert (String.cut "," "," = Some ("", ""));
assert (String.cut "," ",," = Some ("", ","));
assert (String.cut "," ",,," = Some ("", ",,"));
assert (String.cut "," "123" = None);
assert (String.cut "," ",123" = Some ("", "123"));
assert (String.cut "," "123," = Some ("123", ""));
assert (String.cut "," "1,2,3" = Some ("1", "2,3"));
assert (String.cut "," " 1,2,3" = Some (" 1", "2,3"));
assert (String.cut "<>" "" = None);
assert (String.cut "<>" "<>" = Some ("", ""));
assert (String.cut "<>" "<><>" = Some ("", "<>"));
assert (String.cut "<>" "<><><>" = Some ("", "<><>"));
assert (String.rcut "<>" "1" = None);
assert (String.cut "<>" "123" = None);
assert (String.cut "<>" "<>123" = Some ("", "123"));
assert (String.cut "<>" "123<>" = Some ("123", ""));
assert (String.cut "<>" "1<>2<>3" = Some ("1", "2<>3"));
assert (String.cut "<>" " 1<>2<>3" = Some (" 1", "2<>3"));
assert (String.cut "<>" ">>><>>>><>>>><>>>>" =
Some (">>>", ">>><>>>><>>>>"));
assert (String.cut "<->" "<->>->" = Some ("", ">->"));
assert (String.rcut "<->" "<-" = None);
assert (String.cut "aa" "aa" = Some ("", ""));
assert (String.cut "aa" "aaa" = Some ("", "a"));
assert (String.cut "aa" "aaaa" = Some ("", "aa"));
assert (String.cut "aa" "aaaaa" = Some ("", "aaa";));
assert (String.cut "aa" "aaaaaa" = Some ("", "aaaa"));
(* String.rcut *)
assert (try ignore (String.rcut "" ""); false with Invalid_argument _ -> true);
assert (try ignore (String.rcut "" "123"); false with Invalid_argument _ -> true);
assert (String.rcut "," "" = None);
assert (String.rcut "," "," = Some ("", ""));
assert (String.rcut "," ",," = Some (",", ""));
assert (String.rcut "," ",,," = Some (",,", ""));
assert (String.rcut "," "123" = None);
assert (String.rcut "," ",123" = Some ("", "123"));
assert (String.rcut "," "123," = Some ("123", ""));
assert (String.rcut "," "1,2,3" = Some ("1,2", "3"));
assert (String.rcut "," "1,2,3 " = Some ("1,2", "3 "));
assert (String.rcut "<>" "" = None);
assert (String.rcut "<>" "<>" = Some ("", ""));
assert (String.rcut "<>" "<><>" = Some ("<>", ""));
assert (String.rcut "<>" "<><><>" = Some ("<><>", ""));
assert (String.rcut "<>" "1" = None);
assert (String.rcut "<>" "123" = None);
assert (String.rcut "<>" "<>123" = Some ("", "123"));
assert (String.rcut "<>" "123<>" = Some ("123", ""));
assert (String.rcut "<>" "1<>2<>3" = Some ("1<>2", "3"));
assert (String.rcut "<>" "1<>2<>3 " = Some ("1<>2", "3 "));
assert (String.rcut "<>" ">>><>>>><>>>><>>>>" =
Some (">>><>>>><>>>>", ">>>"));
assert (String.rcut "<->" "<->>->" = Some ("", ">->"));
assert (String.rcut "<->" "<-" = None);
assert (String.rcut "aa" "aa" = Some ("", ""));
assert (String.rcut "aa" "aaa" = Some ("a", ""));
assert (String.rcut "aa" "aaaa" = Some ("aa", ""));
assert (String.rcut "aa" "aaaaa" = Some ("aaa", "";));
assert (String.rcut "aa" "aaaaaa" = Some ("aaaa", ""));
```