itertools
[software/python-on-guile.git] / modules / language / python / string.scm
1 (define-module (language python string)
2 #:use-module (parser stis-parser)
3 #:use-module (oop goops)
4 #:use-module (oop pf-objects)
5 #:use-module (language python hash)
6 #:use-module (ice-9 match)
7 #:use-module (language python list)
8 #:use-module (language python exceptions)
9 #:use-module (language python for)
10 #:use-module (language python persist)
11 #:export (py-format py-capitalize py-center py-endswith
12 py-expandtabs py-find py-rfind
13 py-isalnum py-isalpha py-isdigit py-islower
14 py-isspace py-isupper py-istitle py-join py-ljust
15 py-rjust py-format-map
16 py-rljust py-lower py-upper py-lstrip py-rstrip
17 py-partition py-replace py-strip py-title
18 py-rpartitio py-rindex py-split py-rsplit py-splitlines
19 py-startswith py-swapcase py-translate py-zfill
20 pystring-listing <py-string> pystring))
21
22 (define-syntax-rule (aif it p x y) (let ((it p)) (if it x y)))
23
24
25 (define-class <py-string> () str)
26 (name-object <py-string>)
27
28 (cpit <py-string> (o (lambda (o s) (slot-set! o 'str s))
29 (list (slot-ref o 'str))))
30
31 (define-syntax-rule (define-py (f n o . u) code ...)
32 (begin
33 (define-method (f (o <string>) . u) code ...)
34 (define-method (f (o <py-string>) . l) (apply f (slot-ref o 'str) l))
35 (define-method (f (o <p>) . l)
36 (aif it (ref o 'n)
37 (apply it l)
38 (next-method)))))
39
40 (define-py (py-capitalize capitalize s)
41 (let* ((n (len s))
42 (w (make-string n)))
43 (let lp ((i 0) (first? #t))
44 (if (< i n)
45 (let ((ch (string-ref s i)))
46 (if (and first? (char-alphabetic? ch))
47 (begin
48 (string-set! w i (char-upcase ch))
49 (lp (+ i 1) #f))
50 (begin
51 (string-set! w i ch)
52 (lp (+ i 1) first?))))
53 w))))
54
55 (define-py (py-center center o w . l)
56 (let* ((ws (if (pair? l)
57 (car (string->list (car l)))
58 #\space))
59 (n (string-length o))
60 (w (if (< w n) n w))
61 (d (- w n))
62 (e (floor-quotient (- w n) 2))
63 (s (make-string w #\space)))
64 (let lp ((i 0) (j e))
65 (if (< i n)
66 (begin
67 (string-set! s j (string-ref o i))
68 (lp (+ i 1) (+ j 1)))))
69 s))
70
71
72
73 ;;;py-decode
74 ;;;py-encode
75
76
77 (define-py (py-endswith endswith o (suff <string>) . l)
78 (let* ((n (string-length o))
79 (ns (string-length suff))
80 (f (lambda (x) (< x 0) (+ n x) x)))
81 (call-with-values (lambda ()
82 (match l
83 (() (values 0 n ))
84 ((x) (values (f x) n ))
85 ((x y) (values (f x) (f y)))))
86 (lambda (start end)
87 (string-suffix? suff o 0 ns start end)))))
88
89 (define-py (py-startswith startswith o (suff <string>) . l)
90 (let* ((n (string-length o))
91 (ns (string-length suff))
92 (f (lambda (x) (< x 0) (+ n x) x)))
93 (call-with-values (lambda ()
94 (match l
95 (() (values 0 n ))
96 ((x) (values (f x) n ))
97 ((x y) (values (f x) (f y)))))
98 (lambda (start end)
99 (string-prefix? suff o 0 ns start end)))))
100
101 (define-py (py-expandtabs expandtabs s . l)
102 (let* ((tabsize (match l (() 8) ((x) x)))
103 (u (string->list (make-string tabsize #\space)))
104 (n (string-length s)))
105 (let lp ((l (string->list s)) (r '()))
106 (if (pair? l)
107 (let ((x (car l)))
108 (if (eq? x #\tab)
109 (lp (cdr l) (append u r))
110 (lp (cdr l) (cons x r))))
111 (list->string (reverse r))))))
112
113 (define-py (py-find find s sub . l)
114 (let* ((n (string-length s))
115 (f (lambda (x) (< x 0) (+ n x) x)))
116 (call-with-values (lambda ()
117 (match l
118 (() (values 0 n ))
119 ((x) (values (f x) n ))
120 ((x y) (values (f x) (f y)))))
121 (lambda (start end)
122 (aif it (string-contains s sub start end)
123 it
124 -1)))))
125
126 (define-py (py-rfind rfind s sub . l)
127 (let* ((n (string-length s))
128 (s (string-reverse s))
129 (sub (string-reverse sub))
130 (f (lambda (x) (< x 0) (+ n x) x)))
131 (call-with-values (lambda ()
132 (match l
133 (() (values 0 n ))
134 ((x) (values (f x) n ))
135 ((x y) (values (f x) (f y)))))
136 (lambda (start end)
137 (aif it (string-contains s sub start end)
138 (- n it (len sub))
139 -1)))))
140
141 (define formatter #f)
142 (define-py (py-strformat format s . l)
143 (apply (ref formatter 'format) s l))
144
145 (define-py (py-format-map format_map s map)
146 (apply (ref formatter 'vformat) s '() map))
147
148 (define format (lambda (a b) a))
149 (define-py (py-format format s format-string)
150 (format s format-string))
151
152 (define-syntax-rule (mk-is py-isalnum isalnum x ...)
153 (define-py (py-isalnum isalnum s)
154 (and (> (len s) 0)
155 (string-fold
156 (lambda (ch s)
157 (if (or (x ch) ...)
158 s
159 #f))
160 #t s))))
161
162 (mk-is py-isalnum isalnum char-alphabetic? char-numeric?)
163 (mk-is py-isalpha isalpha char-alphabetic?)
164 (mk-is py-isdigit isdigit char-numeric?)
165 (mk-is py-islower islower char-lower-case?)
166 (mk-is py-isspace isspace char-whitespace?)
167 (mk-is py-isupper isupper char-upper-case?)
168
169 (define-py (py-istitle istitle s)
170 (let ((n (len s)))
171 (if ((> n 0))
172 (let lp ((i 0) (space? #t))
173 (if (< i n)
174 (let ((ch (string-ref s i)))
175 (if space?
176 (cond
177 ((char-whitespace? ch)
178 (lp (+ i 1) #t))
179 ((char-upper-case? ch)
180 (lp (+ i 1) #f))
181 (else
182 #f))
183 (cond
184 ((char-whitespace? ch)
185 (lp (+ i 1) #t))
186 ((char-upper-case? ch)
187 #f)
188 ((char-lower-case? ch)
189 (lp (+ i 1) #f))
190 (else
191 #f))))
192 #t))
193 #f)))
194
195
196 (define-py (py-join join s iterator)
197 (string-join (to-list iterator) s))
198
199 (define-py (py-ljust ljust s width . l)
200 (let* ((n (len s))
201 (ch (match l
202 ((x . l)
203 (if (string? x)
204 (string-ref x 0)
205 x))
206 (()
207 #\space))))
208 (if (< width n)
209 (pylist-slice s 0 width 1)
210 (let ((ret (make-string width ch)))
211 (let lp ((i 0))
212 (if (< i n)
213 (begin
214 (string-set! ret i (string-ref s i))
215 (lp (+ i 1)))
216 ret))))))
217
218 (define-py (py-rjust rjust s width . l)
219 (let* ((n (len s))
220 (ch (match l
221 ((x . l)
222 (if (string? x)
223 (string-ref x 0)
224 x))
225 (()
226 #\space))))
227 (if (< width n)
228 (pylist-slice s (- width) (len s) 1)
229 (let ((ret (make-string width ch)))
230 (let lp ((i 0) (j (- width n)))
231 (if (< i n)
232 (begin
233 (string-set! ret j (string-ref s i))
234 (lp (+ i 1) (+ j 1)))
235 ret))))))
236
237 (define-py (py-lower lower s)
238 (string-downcase s))
239
240 (define-py (py-upper upper s)
241 (string-upcase s))
242
243 (define-py (py-lstrip lstrip s . l)
244 (match l
245 (()
246 (string-trim s))
247 ((x . _)
248 (let ((l (map (lambda (x) (if (string? x) (string-ref x 0) x)) x)))
249 (string-trim s (lambda (ch) (member ch l)))))))
250
251 (define-py (py-rstrip rstrip s . l)
252 (match l
253 (()
254 (string-trim-right s))
255 ((x . _)
256 (let ((l (map (lambda (x) (if (string? x) (string-ref x 0) x)) x)))
257 (string-trim-right s (lambda (ch) (member ch l)))))))
258
259 (define-py (py-partition partition s (sep <string>))
260 (let ((n (len s))
261 (m (len sep)))
262 (define (test i)
263 (let lp ((i i) (j 0))
264 (if (< i n)
265 (if (< j m)
266 (if (eq? (string-ref s i) (string-ref sep j))
267 (lp (+ i 1) (+ j 1))
268 #f)
269 #t)
270 #f)))
271 (let lp ((i 0))
272 (if (< i n)
273 (if (test i)
274 (list (pylist-slice s 0 i 1) sep (pylist-slice s (+ i m) n 1))
275 (lp (+ i 1)))
276 (list s "" "")))))
277
278 (define-py (py-partition partition s (sep <py-string>))
279 (py-partition s (slot-ref sep 'str)))
280
281
282 (define-py (py-rpartition rpartition ss (ssep <string>))
283 (let* ((s (string-reverse ss))
284 (sep (string-reverse ssep))
285 (n (len s))
286 (m (len sep)))
287 (define (test i)
288 (let lp ((i i) (j 0))
289 (if (< i n)
290 (if (< j m)
291 (if (eq? (string-ref s i) (string-ref sep j))
292 (lp (+ i 1) (+ j 1))
293 #f)
294 #t)
295 #f)))
296 (let lp ((i 0))
297 (if (< i n)
298 (if (test i)
299 (list (string-reverse
300 (pylist-slice s (+ i m) n 1))
301 ssep
302 (string-reverse
303 (pylist-slice s 0 i 1)))
304 (lp (+ i 1)))
305 (list "" "" s)))))
306
307 (define-py (py-rpartition rpartition s (sep <py-string>))
308 (py-rpartition s (slot-ref sep 'str)))
309
310 (define-py (py-replace replace s old new . l)
311 (let ((n (match l (() #f) ((n . _) n))))
312 (string-join
313 (reverse
314 (let lp ((s s) (r '()))
315 (let ((l (py-partition s old)))
316 (if (equal? (cadr l) "")
317 (cons s r)
318 (lp (list-ref l 2) (cons (car l) r))))))
319 new)))
320
321 (define-py (py-strip strip s . l)
322 (apply py-rstrip (apply py-lstrip s l) l))
323
324 (define-py (py-title title s)
325 (string-titlecase s))
326
327 (define-py (py-rindex rindex s . l)
328 (let ((n (len s)))
329 (- n (apply pylist-index (string-reverse s) l) 1)))
330
331
332
333 (define-py (py-split split s . l)
334 (define ws (f+ (f-reg "[ \t\n]")))
335 (define r
336 (f-or! (f-seq f-eof (f-out '()))
337 (f-cons (f-seq (mk-token (f* (f-reg! "."))) f-eof) (f-out '()))))
338 (define (u ws) (mk-token (f+ (f-not! ws))))
339 (define (tok ws i)
340 (if (= i 0)
341 (f-list (mk-token (f* (f-reg! "."))))
342 (let ((e (mk-token (f* (f-not! ws)))))
343 (f-seq (f? ws)
344 (f-cons e
345 (let lp ((i i))
346 (if (> (- i 1) 0)
347 (f-or! (f-seq (f? ws) f-eof (f-out '()))
348 (f-cons (f-seq ws e) (Ds (lp (- i 1)))))
349 r)))))))
350
351 (define N 1000000000000)
352 (let ((e (call-with-values
353 (lambda ()
354 (match l
355 (() (values ws N))
356 ((sep) (values (f-tag sep) N))
357 ((sep n) (values (f-tag sep) n))))
358 tok)))
359 (parse s e)))
360
361 (define-py (py-rsplit rsplit s . l)
362 (reverse
363 (map string-reverse
364 (apply py-split
365 (string-reverse s)
366 (match l
367 (() '())
368 ((sep . l) (cons (string-reverse sep) l)))))))
369
370
371 (define-py (py-splitlines splitlines s . l)
372 (let ((n (len s))
373 (keep? (match l
374 ((#:keepends v)
375 v)
376 ((v)
377 v)
378 (_ #f))))
379 (let lp ((i 0) (r '()) (old 0))
380 (if (< i n)
381 (let ((ch (string-ref s i)))
382 (if (eq? ch #\newline)
383 (if keep?
384 (lp (+ i 1)
385 (cons
386 (pylist-slice s old (+ i 1) 1)
387 r)
388 (+ i 1))
389 (lp (+ i 1)
390 (cons
391 (pylist-slice s old i 1)
392 r)
393 (+ i 1)))
394 (lp (+ i 1) r old)))
395 (reverse r)))))
396
397 (define-py (py-swapcase swapcase s)
398 (list->string
399 (string-fold
400 (lambda (ch s)
401 (cons
402 (cond
403 ((char-upper-case? ch)
404 (char-downcase ch))
405 ((char-lower-case? ch)
406 (char-upcase ch))
407 (else ch))
408 s))
409 '()
410 s)))
411
412 (define-py (py-translate translate s table . l)
413 (let* ((n (len s))
414 (w (make-string n))
415 (t (if (eq? table None) #f table))
416 (d (match l (() #f) ((x) x))))
417 (define (tr ch)
418 (define (e)
419 (if t
420 (let ((i (char->integer ch)))
421 (if (< i (string-length t))
422 (string-ref t i)
423 ch))
424 ch))
425
426 (if d
427 (if (string-contains d (list->string (list ch)))
428 #f
429 (e))
430 (e)))
431
432 (let lp ((i 0) (k 0))
433 (if (< i n)
434 (let ((ch (tr (string-ref s i))))
435 (if ch
436 (begin
437 (string-set! w k ch)
438 (lp (+ i 1) (+ k 1)))
439 (lp (+ i 1) k)))
440 (if (= k n)
441 w
442 (pylist-slice w 0 k 1))))))
443
444 (define-syntax-rule (a b x y) (b (symbol->string x) (symbol->string y)))
445
446 (define-syntax-rule (mkop op)
447 (begin
448 (define-method (op (s1 <string>) (s2 <py-string>))
449 (op s1 (slot-ref s2 'str)))
450 (define-method (op (s2 <py-string>) (s1 <string>))
451 (op s1 (slot-ref s2 'str)))))
452
453 (mkop <)
454 (mkop <=)
455 (mkop >)
456 (mkop >=)
457 (mkop +)
458 (mkop *)
459
460 (define-method (< (s1 <string>) (s2 <string>)) (string-ci< s1 s2))
461 (define-method (<= (s1 <string>) (s2 <string>)) (string-ci<= s1 s2))
462 (define-method (> (s1 <string>) (s2 <string>)) (string-ci> s1 s2))
463 (define-method (>= (s1 <string>) (s2 <string>)) (string-ci>= s1 s2))
464
465 (define-method (< (s1 <symbol>) (s2 <symbol>)) (a string-ci< s1 s2))
466 (define-method (<= (s1 <symbol>) (s2 <symbol>)) (a string-ci<= s1 s2))
467 (define-method (> (s1 <symbol>) (s2 <symbol>)) (a string-ci> s1 s2))
468 (define-method (>= (s1 <symbol>) (s2 <symbol>)) (a string-ci>= s1 s2))
469
470
471 (define-py (py-zfill zfill s width)
472 (let* ((n (len s))
473 (w (pylist-slice s 0 n 1)))
474 (let lp ((i 0))
475 (if (< i n)
476 (let ((ch (string-ref s i)))
477 (if (char-numeric? ch)
478 (let lp ((j (max 0 (- i width))))
479 (if (< j i)
480 (begin
481 (string-set! w j #\0)
482 (lp (+ j 1)))
483 w))
484 (lp (+ i 1))))
485 s))))
486
487 (define-python-class string (<py-string>)
488 (define __init__
489 (case-lambda
490 ((self s)
491 (cond
492 ((is-a? s <py-string>)
493 (slot-set! self 'str (slot-ref s 'src)))
494 ((is-a? s <string>)
495 (slot-set! self 'str s))))))
496
497 (define __repr__
498 (lambda (self)
499 (slot-ref self 'str))))
500
501 (name-object string)
502
503 (define pystring string)
504
505 (define-method (py-class (o <string>)) string)
506 (define-method (py-class (o <py-string>)) string)
507
508 (define-method (pyhash (o <py-string>)) (hash (slot-ref o 'str) pyhash-N))
509
510 (define-method (py-equal? (o <py-string>) x)
511 (equal? (slot-ref o 'str) x))
512 (define-method (py-equal? x (o <py-string>))
513 (equal? (slot-ref o 'str) x))
514
515 (define-class <string-iter> (<py-string>) str i d)
516 (name-object <string-iter>)
517 (cpit <string-iter> (o
518 (lambda (o str i d)
519 (slot-set! o 'str str)
520 (slot-set! o 'i i )
521 (slot-set! o 'd d ))
522 (list
523 (slot-ref o 'str)
524 (slot-ref o 'i)
525 (slot-ref o 'd))))
526
527
528 (define-method (write (o <string-iter>) . l)
529 (define port (if (null? l) #t (car l)))
530 (for ((x : o)) ((l '()))
531 (cons (string-ref x 0) l)
532 #:final
533 ((@ (guile) format) port "iter(~s)" (list->string (reverse l)))))
534
535 (define-method (wrap-in (o <string-iter> ))
536 (let ((out (make <string-iter>)))
537 (slot-set! out 'str (slot-ref o 'str))
538 (slot-set! out 'i (slot-ref o 'i))
539 (slot-set! out 'd (slot-ref o 'd))
540 out))
541
542 (define-method (wrap-in (s <string>))
543 (let ((out (make <string-iter>)))
544 (slot-set! out 'str s)
545 (slot-set! out 'i 0)
546 (slot-set! out 'd 1)
547 out))
548
549 (define-method (py-reversed (s <string>))
550 (let ((out (make <string-iter>)))
551 (slot-set! out 'str s)
552 (slot-set! out 'i (- (string-length s) 1))
553 (slot-set! out 'd -1)
554 out))
555
556 (define-method (next (o <string-iter>))
557 (let ((i (slot-ref o 'i ))
558 (d (slot-ref o 'd))
559 (str (slot-ref o 'str)))
560 (if (> d 0)
561 (if (< i (string-length str))
562 (let ((ret (string-ref str i)))
563 (slot-set! o 'i (+ i d))
564 (list->string (list ret)))
565 (throw StopIteration))
566 (if (>= i 0)
567 (let ((ret (string-ref str i)))
568 (slot-set! o 'i (+ i d))
569 (list->string (list ret)))
570 (throw StopIteration)))))
571
572 (define (pystring-listing)
573 (let ((l (to-pylist
574 (map symbol->string
575 '(__add__ __class__ __contains__ __delattr__ __doc__
576 __eq__ __format__ __ge__ __getattribute__
577 __getitem__ __getnewargs__ __getslice__ __gt__
578 __hash__ __init__ __le__ __len__ __lt__ __mod__
579 __mul__ __ne__ __new__ __reduce__ __reduce_ex__
580 __repr__ __rmod__ __rmul__ __setattr__ __sizeof__
581 __str__ __subclasshook__
582 _formatter_field_name_split _formatter_parser
583 capitalize center count decode encode endswith
584 expandtabs find format index isalnum isalpha
585 isdigit islower isspace istitle isupper join
586 ljust lower lstrip partition replace rfind rindex
587 rjust rpartition rsplit rstrip split splitlines
588 startswith strip swapcase format_map
589 title translate upper zfill)))))
590 (pylist-sort! l)
591 l))
592
593