Skip to content

Commit 859a6c7

Browse files
authored
Merge pull request #278 from puripuri2100/add-some-string-fun
Add some string functions
2 parents aae115a + 551f024 commit 859a6c7

File tree

3 files changed

+227
-10
lines changed

3 files changed

+227
-10
lines changed

__test__/__snapshots__/regression.test.js.snap

+12
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ exports[`Check compiler outputs 1`] = `
99
[debug.log] 1
1010
[debug.log] ==== String ====
1111
[debug.log] abc
12+
[debug.log] a;b;c
1213
[debug.log] true
1314
[debug.log] spam
1415
[debug.log] ham
@@ -21,6 +22,17 @@ exports[`Check compiler outputs 1`] = `
2122
[debug.log] true
2223
[debug.log] true
2324
[debug.log] true
25+
[debug.log] true
26+
[debug.log] false
27+
[debug.log] false
28+
[debug.log] abc
29+
[debug.log] 
30+
[debug.log] abc 
31+
[debug.log] abc
32+
[debug.log] GRüßE, JüRGEN
33+
[debug.log] grÜße, jÜrgen
34+
[debug.log] TiTle
35+
[debug.log] tiTle
2436
[debug.log] ==== List ====
2537
[debug.log] 
2638
[debug.log] 1

__test__/satysrc/generic.saty

+13-1
Original file line numberDiff line numberDiff line change
@@ -54,13 +54,25 @@ let () = Debug.log (String.of-int (Ref.get r)) in % 1
5454

5555
let () = Debug.log `==== String ====` in
5656
let () = Debug.log (String.concat [`a`; `b`; `c`;]) in
57+
let () = Debug.log (String.concat ?:(`;`) [`a`; `b`; `c`;]) in
5758
let () = Debug.log (String.of-bool (String.is-empty ` `)) in % true
5859
let _ = String.split-by (Char.make `;`) `spam;ham;eggs;` |> List.map Debug.log in
5960
let _ = String.to-list `abc` |> List.map (fun c -> (c |> String.of-char |> Debug.log)) in
6061
let () = String.(`a` < `b`) |> Bool.to-string |> Debug.log in % true
6162
let () = String.(`ab` < `ba`) |> Bool.to-string |> Debug.log in % true
6263
let () = String.(`aab` < `aba`) |> Bool.to-string |> Debug.log in % true
6364
let () = String.(`bbb` < `bbba`) |> Bool.to-string |> Debug.log in % true
65+
let () = String.contains `abc` `1abcdef` |> Bool.to-string |> Debug.log in % true
66+
let () = String.contains `abc` `abdef` |> Bool.to-string |> Debug.log in % false
67+
let () = String.contains `abc` `ef` |> Bool.to-string |> Debug.log in % false
68+
let () = String.trim #` abc `# |> Debug.log in % |abc|
69+
let () = String.trim #` `# |> Debug.log in % ||
70+
let () = String.trim-start #` abc `# |> Debug.log in % |abc |
71+
let () = String.trim-end #` abc `# |> Debug.log in % | abc|
72+
let () = String.uppercase-ascii `Grüße, Jürgen` |> Debug.log in % GRüßE, JüRGEN
73+
let () = String.lowercase-ascii `GRÜßE, JÜRGEN` |> Debug.log in % grÜße, jÜrgen
74+
let () = String.capitalize-ascii `tiTle` |> Debug.log in % TiTle
75+
let () = String.uncapitalize-ascii `TiTle` |> Debug.log in % tiTle
6476

6577
let () = Debug.log `==== List ====` in
6678
let lst = [1;3;2;4;5] in
@@ -358,7 +370,7 @@ let () = Debug.log `==== TreeSet ====` in
358370
% REMARK:
359371
% This test relies on the fact that the order of elements of a result from TreeSet.to-list is
360372
% level-order (BFS). If the implementation is changed, the following tests have to be updated.
361-
let p s = s |> TreeSet.to-list |> List.map String.of-int |> List.intersperse `,` |> String.concat |> Debug.log in
373+
let p s = s |> TreeSet.to-list |> List.map String.of-int |> List.intersperse `,` |> (fun l -> String.concat l) |> Debug.log in
362374
let s = TreeSet.empty in
363375
let () = p s in
364376
let s = TreeSet.of-list Int.ord [3;2;3;1] in

src/string.satyg

+202-9
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ module String : sig
2626
val of-char : Char.t -> string
2727
val of-length : length -> string
2828
val append : string -> string -> string
29-
val concat : string list -> string
29+
val concat : string ?-> string list -> string
3030
val is-empty : string -> bool
3131
val starts-with : string -> string -> bool
3232
val ends-with : string -> string -> bool
@@ -38,6 +38,17 @@ module String : sig
3838
val split-by : Char.t -> string -> string list
3939
val lines : string -> string list
4040
val index : Char.t -> string -> int option
41+
val make : int -> Char.t -> string
42+
val init : int -> (int -> Char.t) -> string
43+
val get : int -> string -> Char.t option
44+
val contains : string -> string -> bool
45+
val trim : string -> string
46+
val trim-start : string -> string
47+
val trim-end : string -> string
48+
val uppercase-ascii : string -> string
49+
val lowercase-ascii : string -> string
50+
val capitalize-ascii : string -> string
51+
val uncapitalize-ascii : string -> string
4152
% val byte-length : string -> int
4253
% val sub-bytes : int -> int -> string -> string
4354
end = struct
@@ -53,9 +64,22 @@ end = struct
5364
let of-char = Char.to-string
5465
let append s1 s2 = s1 ^ s2
5566

56-
let-rec concat xs = match xs with
57-
| [] -> empty
58-
| s :: xs -> s ^ concat xs
67+
68+
69+
let concat ?:s xs =
70+
let s =
71+
match s with
72+
| None -> empty
73+
| Some(s) -> s
74+
in
75+
let-rec sub xs =
76+
match xs with
77+
| [] -> empty
78+
| [x] -> x
79+
| x :: xs -> x ^ s ^ sub xs
80+
in
81+
sub xs
82+
5983

6084
let is-empty s =
6185
equal s empty
@@ -71,13 +95,12 @@ end = struct
7195
(s-len >= p-len) &&&- (fun () -> equal (s |> sub (s-len - 1 - p-len) p-len) p)
7296

7397
let to-list s =
74-
let-rec go i acc = (match i with
75-
| 0 -> acc
76-
| _ -> go (i - 1) (Char.at (i - 1) s :: acc)) in
77-
go (length s) []
98+
s
99+
|> string-explode
100+
|> List.map Char.of-codepoint
78101

79102
let of-list chars =
80-
chars |> List.map Char.to-string |> concat
103+
chars |> List.map Char.to-string |> (fun slst -> concat slst)
81104

82105
let pow n s =
83106
let-rec go i acc = if i == n then acc else go (i + 1) (acc ^ s) in
@@ -103,6 +126,176 @@ end = struct
103126

104127
let lines = split-by Char.newline
105128

129+
130+
let-rec make n c =
131+
if n <= 0 then
132+
empty
133+
else
134+
Char.to-string c ^ make (n - 1) c
135+
136+
137+
let init n f =
138+
let-rec sub m f =
139+
if m >= n then
140+
empty
141+
else
142+
Char.to-string (f m) ^ sub (m + 1) f
143+
in
144+
sub 0 f
145+
146+
147+
let get n str =
148+
str
149+
|> to-list
150+
|> List.nth n
151+
152+
153+
154+
155+
% Quick-Search
156+
% こちらを参考に実装:https://www.m3tech.blog/entry/2020/09/28/120000
157+
let contains s str =
158+
% 検索する語と検索される語が先頭から一致するかどうかを判定する
159+
% 一致しない場合は先頭の文字を渡す
160+
let-rec search-and-get-next-char is-eq clst slst =
161+
match (clst, slst) with
162+
| ([], []) -> (is-eq, None)
163+
| ([], s::_) -> (is-eq, Some(s))
164+
| (_, []) -> (false, None)
165+
| (c::cs, s::ss) -> (
166+
if Char.equal c s && is-eq then
167+
search-and-get-next-char true cs ss
168+
else
169+
search-and-get-next-char false cs ss
170+
)
171+
in
172+
173+
% 検索される語の先頭の文字が、検索する語の中で何番目にあたるかを調べる
174+
% 検索される後の先頭の文字が、検索する語の中にない場合はNoneが返る
175+
let-rec find-next-char-pos n n-opt c clst =
176+
match clst with
177+
| x::xs -> (
178+
if Char.equal x c then
179+
find-next-char-pos (n + 1) (Some n) c xs
180+
else
181+
find-next-char-pos (n + 1) None c xs
182+
)
183+
| [] -> n-opt
184+
in
185+
186+
let-rec shift n lst =
187+
if n <= 0 then
188+
lst
189+
else
190+
match lst with
191+
| [] -> []
192+
| _::xs -> shift (n - 1) xs
193+
in
194+
195+
let clst = to-list s in
196+
let-rec sub l =
197+
match search-and-get-next-char true clst l with
198+
| (true, _) -> true
199+
| (false, None) -> false
200+
| (false, Some(c)) -> (
201+
let n-opt = find-next-char-pos 0 None c clst in
202+
let n =
203+
match n-opt with
204+
| Some(n) -> List.length clst - n
205+
| None -> List.length clst + 1
206+
in
207+
let new-l = shift n l in
208+
sub new-l
209+
)
210+
in
211+
sub (to-list str)
212+
213+
214+
let-rec space-len n clst =
215+
match clst with
216+
| c::xs -> (
217+
if Char.is-space c then
218+
space-len (n + 1) xs
219+
else
220+
n
221+
)
222+
| _ -> n
223+
224+
let trim str =
225+
let len = length str in
226+
let lst = to-list str in
227+
let rev-lst = List.reverse lst in
228+
let start-space-len = space-len 0 lst in
229+
let end-space-len = space-len 0 rev-lst in
230+
let len = len - start-space-len - end-space-len in
231+
let len = if len < 0 then 0 else len in
232+
sub start-space-len len str
233+
234+
let trim-start str =
235+
let len = length str in
236+
let lst = to-list str in
237+
let start-space-len = space-len 0 lst in
238+
let len = len - start-space-len in
239+
sub start-space-len len str
240+
241+
let trim-end str =
242+
let len = length str in
243+
let lst = str |> to-list |> List.reverse in
244+
let start-space-len = space-len 0 lst in
245+
let len = len - start-space-len in
246+
sub 0 len str
247+
248+
249+
let uppercase-ascii str =
250+
str
251+
|> to-list
252+
|> List.map (fun c -> (
253+
let n = Char.to-codepoint c in
254+
if 0x61 <= n && n <= 0x7A then
255+
Char.of-codepoint (n - 0x20)
256+
else
257+
c
258+
))
259+
|> of-list
260+
261+
let lowercase-ascii str =
262+
str
263+
|> to-list
264+
|> List.map (fun c -> (
265+
let n = Char.to-codepoint c in
266+
if 0x41 <= n && n <= 0x5A then
267+
Char.of-codepoint (n + 0x20)
268+
else
269+
c
270+
))
271+
|> of-list
272+
273+
let capitalize-ascii str =
274+
str
275+
|> to-list
276+
|> List.mapi (fun i c -> (
277+
let n = Char.to-codepoint c in
278+
if i == 0 && 0x61 <= n && n <= 0x7A then
279+
Char.of-codepoint (n - 0x20)
280+
else
281+
c
282+
))
283+
|> of-list
284+
285+
let uncapitalize-ascii str =
286+
str
287+
|> to-list
288+
|> List.mapi (fun i c -> (
289+
let n = Char.to-codepoint c in
290+
if i == 0 && 0x41 <= n && n <= 0x5A then
291+
Char.of-codepoint (n + 0x20)
292+
else
293+
c
294+
))
295+
|> of-list
296+
297+
298+
106299
let index c s =
107300
let cs = to-list s in
108301
let-rec aux cs acc = match cs with

0 commit comments

Comments
 (0)