Source file ezString.ml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
(**************************************************************************)
(*                                                                        *)
(*   Typerex Libraries                                                    *)
(*                                                                        *)
(*   Copyright 2011-2017 OCamlPro SAS                                     *)
(*                                                                        *)
(*   All rights reserved.  This file is distributed under the terms of    *)
(*   the GNU Lesser General Public License version 2.1, with the          *)
(*   special exception on linking described in the file LICENSE.          *)
(*                                                                        *)
(**************************************************************************)

open EzCompat
open String

(* Character predicates *)
let for_all f s =
  let res = ref true in
  for i = 0 to length s - 1 do
    res := !res && f s.[i]
  done;
  !res

let exists f s =
  let res = ref false in
  for i = 0 to length s - 1 do
    res := !res || f s.[i]
  done;
  !res

(* The substring before [pos] (the character at position [pos] is discarded) *)
let before s pos =
  sub s 0 pos

(* The substring after [pos] (the character at position [pos] is discarded) *)
let after s pos =
  sub s (pos + 1) (length s - pos - 1)

let rec strneql s1 s2 len =
  len = 0 || (
    let len = len - 1 in
    s1.[len] = s2.[len] && strneql s1 s2 len)

let starts_with s ~prefix =
  let len1 = length s in
  let len2 = length prefix in
  len2 <= len1 && strneql s prefix len2

let ends_with s ~suffix =
  let rec aux offset len =
    len = 0 || (
      let len = len - 1 in
      s.[offset+len] = suffix.[len] && aux offset len) in
  let len1 = length s in
  let len2 = length suffix in
  len2 <= len1 && aux (len1 - len2) len2

(* Cut the string at position [pos] (the character at position [pos]
   is kept if [keep]) *)
let cut s pos =
  try
    before s pos, after s pos
  with _ -> s, ""

let cut_at s c =
  try
    let pos = index s c in
    cut s pos
  with _ -> s, ""

let rcut_at s c =
  try
    let pos = rindex s c in
    cut s pos
  with _ -> s, ""

let split s c =
  let len = String.length s in
  match String.index s c with
  | exception Not_found ->
    if len = 0 then [] else [ s ]
  | pos ->
    let rec iter pos to_rev =
      match String.index_from s pos c with
      | exception Not_found ->
        List.rev ( String.sub s pos ( len - pos ) :: to_rev )
      | pos2 ->
        iter ( pos2 + 1 )
          ( String.sub s pos ( pos2 - pos ) :: to_rev )
    in
    iter (pos+1) [ String.sub s 0 pos ]

let _ =
  assert (split "" 'o' = []);
  assert (split "o" 'o' = [""; ""]);
  assert (split "toto" 'o' = ["t"; "t"; ""]);
  assert (split "ototo" 'o' = [""; "t"; "t"; ""]);
  assert (split "tot" 'o' = ["t"; "t"]);
  ()

let split_simplify s c =
  let len = String.length s in
  let rec iter pos to_rev =
    if pos = len then List.rev to_rev else
      match try
              Some ( String.index_from s pos c )
        with Not_found -> None
      with
          Some pos2 ->
            if pos2 = pos then iter (pos+1) to_rev else
              iter (pos2+1) ((String.sub s pos (pos2-pos)) :: to_rev)
        | None -> List.rev ( String.sub s pos (len-pos) :: to_rev )
  in
  iter 0 []

let _ =
  assert (split_simplify "" 'o' = []);
  assert (split_simplify "toto" 'o' = ["t"; "t"]);
  assert (split_simplify "ototo" 'o' = ["t"; "t"]);
  assert (split_simplify "tot" 'o' = ["t"; "t"]);
  ()

let chop_prefix s ~prefix =
  if starts_with s ~prefix then
    let prefix_len = String.length prefix in
    let len = String.length s in
    Some ( String.sub s prefix_len (len - prefix_len) )
  else
    None

let chop_suffix s ~suffix =
  if ends_with s ~suffix then
    let suffix_len = String.length suffix in
    let len = String.length s in
    Some ( String.sub s 0 (len - suffix_len) )
  else
    None