Source file String_util.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
let title_case_word s =
let did_uppercase = ref false in
let rec loop buf s i max =
if i > max then Buffer.contents buf else
let dec = String.get_utf_8_uchar s i in
let u = Uchar.utf_decode_uchar dec in
let should_ignore = Uucp.Case.is_case_ignorable u || not (Uucp.Case.is_cased u) in
let () =
match should_ignore || !did_uppercase with
| true ->
Buffer.add_utf_8_uchar buf u
| false ->
did_uppercase := true;
match Uucp.Case.Map.to_upper u with
| `Self -> Buffer.add_utf_8_uchar buf u
| `Uchars us -> List.iter (Buffer.add_utf_8_uchar buf) us
in
loop buf s (i + Uchar.utf_decode_length dec) max
in
let buf = Buffer.create @@ String.length s * 2 in
loop buf s 0 @@ String.length s - 1
let sentence_case str =
let words = String.split_on_char ' ' str in
String.concat " " @@ List.mapi (fun i word -> if i = 0 then title_case_word word else word) words
let trim_newlines str =
let rec process_lines lines =
match lines with
| [] -> []
| "" :: lines -> process_lines lines
| _ -> lines
in
let lines = String.split_on_char '\n' str in
String.concat "\n" @@ List.rev @@ process_lines @@ List.rev @@ process_lines lines
let trim_trailing_whitespace str =
let rec process_chars rstr =
match rstr with
| '\n' :: rstr -> process_chars rstr
| ' ' :: rstr -> process_chars rstr
| '\t' :: rstr -> process_chars rstr
| _ -> List.rev rstr
in
let n = String.length str in
let chars = List.rev @@ List.init n (String.get str) in
String.of_seq @@ List.to_seq @@ process_chars @@ chars