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
138
139
140
[@@@warning "@A"]
module String = Stdcompat.String
let len = Stdcompat.String.length
let get (s: string) (pos: int) : char =
let l = len s in
if l <= pos || pos < ~-l then
raise (Exn.IndexError "string index out of range")
else
let pos = if pos >= 0 then pos else l + pos in
Stdcompat.String.get s pos
let translate_bound (n: int option) (l: int) (left: bool) : int =
match left, n with
| true, None -> 0
| false, None -> l - 1
| _, Some n ->
if n >= 0 then
min (l-1) n
else
max 0 (l - n)
let startswith (prefix: string) (s: string) : bool =
if String.length prefix > String.length s then
false
else
prefix = String.sub s 0 (String.length prefix)
let endswith (suffix: string) (s: string) : bool =
if String.length suffix > String.length s then
false
else
suffix = String.sub s (String.length s - String.length suffix) (String.length suffix)
let split ?(sep: string option) s : string list =
let r = ref [] in
let j = ref (String.length s) in
let sep, o = match sep with Some sep -> sep, true | None -> " ", false in
for i = String.length s - 1 downto 0 do
if String.(contains sep (unsafe_get s i)) then begin
r := String.sub s (i + 1) (!j - i - 1) :: !r;
j := i
end
done;
let res = String.sub s 0 !j :: !r in
if o then
res
else
Stdcompat.List.filter ((<>) "") res
let slice ?(start: int option) ?(stop: int option) ?(step: int = 1) (s: string) : string =
Helpers.Slice.slice
?start ?stop ~step ~sub:String.sub
String.length String.get
(Helpers.Slice.Set (fun i c b -> Bytes.set b i c)) (fun l -> Bytes.make l ' ') Bytes.to_string s
let find ?(start: int option) ?(stop: int option) (sub: string) (s: string) : int =
let l = String.length s in
let start = translate_bound start l true in
let stop = translate_bound stop l false in
try
NoPlato.Str.(search_forward (regexp_string sub) (String.sub s start (stop - start)) start)
with Not_found -> -1
let rfind ?(start: int option) ?(stop: int option) (sub: string) (s: string) : int =
let l = String.length s in
let start = translate_bound start l true in
let stop = translate_bound stop l false in
try
NoPlato.Str.(search_backward (regexp_string sub) (String.sub s start (stop - start)) stop)
with Not_found -> -1
let lstrip ?(chars: string = " ") (s: string) : string =
let i = ref 0 in
while !i < String.length s && String.contains chars s.[!i] do
incr i
done;
NoPlato.Str.string_after s !i
let rstrip ?(chars: string = " ") (s: string) : string =
let i = ref (String.length s) in
while !i >= 1 && String.contains chars s.[!i - 1] do
decr i
done;
NoPlato.Str.string_before s !i
let strip ?(chars: string = " ") (s: string) : string =
s |> lstrip ~chars |> rstrip ~chars
let partition (sep: string) (s: string) : string * string * string =
let open NoPlato.Str in
let l : split_result list = full_split (regexp_string sep) s in
let join (l: split_result list) : string =
l
|> Stdcompat.List.map (function Text t -> t | Delim t -> t)
|> String.concat ""
in
match l with
| [] -> "", "", ""
| [Text t] -> t, "", ""
| [Delim t] -> "", t, ""
| Text before :: Delim sep :: q -> before, sep, join q
| Text _ :: Text _ :: _ -> failwith "absurd"
| Delim sep :: q -> "", sep, join q
let rpartition (sep: string) (s: string) : string * string * string =
let open NoPlato.Str in
let l : split_result list = full_split (regexp_string sep) s in
let join (l: split_result list) : string =
l
|> Stdcompat.List.map (function Text t -> t | Delim t -> t)
|> String.concat ""
in
match Stdcompat.List.rev l with
| [] -> "", "", ""
| [Text t] -> "", "", t
| [Delim t] -> "", t, ""
| Text after :: Delim sep :: q -> q |> Stdcompat.List.rev |> join, sep, after
| Text _ :: Text _ :: _ -> failwith "absurd"
| Delim sep :: q -> join q, sep, ""
let replace (old: string) (new_: string) (s: string) : string =
NoPlato.Str.(global_replace (regexp_string old) (quote new_) s)
let isspace (s: string) : bool =
if len s = 0 then
false
else
let exception False in
match String.iter (fun c -> if Stdcompat.String.contains " \t\n\r\x0b\x0c" c |> not then raise False) s with
| () -> true
| exception False -> false
let at (s: string) (n: int) : string =
Stdcompat.String.make 1 s.[n]
let bool (s: string) : bool =
s <> ""