File: strings.scm

package info (click to toggle)
sdc 1.0.8beta-8
  • links: PTS
  • area: contrib
  • in suites: slink
  • size: 1,400 kB
  • ctags: 874
  • sloc: lisp: 8,120; ansic: 967; makefile: 671; perl: 136; sh: 50
file content (207 lines) | stat: -rwxr-xr-x 6,837 bytes parent folder | download
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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
(module strings
	(export
	 (string-find-string str substr . optional-start)
	 (string-find-laststring str substr . optional-start)
	 (string-find-char str chr . optional-start)
	 (string-find-lastchar str chr . optional-start)
	 (string-replw str width)
	 (string-left s1 width . s2)
	 (string-tr-all str from to)
	 (string-split-string str sub . start)
	 (string-split-whitespace str)
	 (strings-join strings gap)
	 (string-split-lines str width)
	 fill-column
	 fill-prefix
	 (fill-split-lines str)
	 ))

; String Handling

(define (string-find-string str substr . optional-start)
  (let* ((start (if (pair? optional-start) (car optional-start) 0))
	 (len-substr (string-length substr))
	 (len-str (string-length str))
	 (max (- len-str len-substr)))
    (let loop ((left start))
      (cond ((> left max) #f)
	    ((string=? (substring str left (+ left len-substr)) substr) left)
	    (else (loop (+ 1 left)))))))

(define (string-find-laststring str substr . optional-start)
  (let* ((len-substr (string-length substr))
	 (len-str (string-length str))
	 (start (- len-str
		   (if (pair? optional-start)
		       (car optional-start) 0)
		   len-substr)))
    (let loop ((left start))
      (cond ((< left 0) #f)
	    ((string=? (substring str left (+ left len-substr)) substr) left)
	    (else (loop (- left 1)))))))

(define (string-find-char str chr . start-pos)
  (let ((len (string-length str)))
    (let find ((pos (if (pair? start-pos) (car start-pos) 0)))
      (cond ((>= pos len) #f)
	    ((char=? (string-ref str pos) chr) pos)
	    (else (find (+ 1 pos)))))))

(define (string-find-lastchar str chr . start-pos)
  (let find ((pos (- (if (pair? start-pos) (car start-pos) 
			 (string-length str)) 1)))
      (cond ((< pos 0) #f)
	    ((char=? (string-ref str pos) chr) pos)
	    (else (find (- pos 1))))))

;;;+f
;;; Geneate a string which is `width' characters long consisting on the
;;; given string `str'.  For example :-
;;;   (string-replw "abc" 10) == "abcabcabca"
;;;   (string-replw "abc" 1)  == "a"
;;;   (string-replw "abc" 0)  == ""
;;;   (string-replw ""    1)  == ""
;;;-f
(define (string-replw str width)
  (if (string=? str "")
      ""
      (let ((str-len (string-length str)))
	(let loop ((result "") (size 0))
	  (cond ((= size width) result)
		((> size width) (substring result 0 width))
		(else (loop (string-append result str) (+ size str-len))))))))

;;;+f
;;; Produce a string of size `width' in which the string `s1' is positioned
;;; at the left and `s2' is used to pad out the remaining characters to
;;; the right.  For example :-
;;;   (string-left "Detroit" 10 "+") == "Detroit+++"
;;;   (string-left "Detroit" 6)      == "Detroi"
;;; Based on the Icon function left(s1, i, s2)
;;;-f
(define (string-left s1 width . s2)
  (let ((padding (if (pair? s2) (car s2) " "))
	(str-len (string-length s1)))
    (cond ((> width str-len)
	   (string-append s1 (string-replw padding (- width str-len))))
	  ((< width str-len) (substring s1 0 width))
	  (else s1))))
;;;
;;; Translate all characters in string `str' which appear in string
;;; `from' into the character at the same position within string `to'.
;;; This is simmilar to what the `tr' program does.
;;; `from' and `to' are required to have equal length, tough
;;; resricting what `tr' does.
;;;
(define (string-tr-all str from to)
  (let ((from-len (string-length from))
	(len (string-length str)))
    (if (not (eqv? from-len (string-length to)))
	(error 'string-tr-all
	       "Strings `from' and `to' have different length."
	       (cons from to)))
    (do ((res (make-string len))
	 (i 0 (+ i 1)))
	((= i len) res)
      (string-set! res i
		   (let* ((c (string-ref str i))
			  (tr (string-find-char from c)))
		     (if tr (string-ref to tr) c))))))

(define (string-split-string str sub . start)
  (letrec ((stl (string-length str))
	   (sul (string-length sub))
	   (splsu (lambda (s) 
		    (let ((end (string-find-string str sub s)))
		      (cond
		       ((not end) (list (substring str s stl)))
		       ((= s end) (splsu (+ end sul)))
		       ((= stl (+ end sul)) (list (substring str s end)))
		       (else (cons (substring str s end) 
				   (splsu (+ end sul)))))))))
    (splsu (if (pair? start) (car start) 0))))


;;; The Scheme below is a loose translation of the following Python code
;;; by Guido van Rossum, CWI Amsterdam <guido@cwi.nl>
;;;
;;; # Split a string into a list of space/tab-separated words
;;; # NB: split(s) is NOT the same as splitfields(s, ' ')!
;;; def split(s):
;;;	res = []
;;;	i, n = 0, len(s)
;;;	while i < n:
;;;		while i < n and s[i] in whitespace: i = i+1
;;;		if i = n: break
;;;		j = i
;;;		while j < n and s[j] not in whitespace: j = j+1
;;;		res.append(s[i:j])
;;;		i = j
;;;	return res
;;;+f
;;; Returns a list of whitespace delimited words in the string `str'.
;;; If the string is empty or contains only whitespace, then
;;; it returns the empty list.
;;;-f
(define (string-split-whitespace str)
  (define (skip-whitespace str pos)
    (cond ((zero? pos) pos)
	  ((char-whitespace? (string-ref str pos))
	   (skip-whitespace str (- pos 1)))
	  (else pos)))
  (define (skip-non-whitespace str pos)
    (cond ((zero? pos)
	   (if (char-whitespace? (string-ref str pos))
	       (+ 1 pos)
	       pos))
	  ((char-whitespace? (string-ref str pos)) (+ 1 pos))
	  (else (skip-non-whitespace str (- pos 1)))))
      (define (string-split-tr str pos result)
    (let ((end (skip-whitespace str pos)))
      (if (zero? end)
	  result
	  (let* ((start (skip-non-whitespace str end))
		 (new-result (cons (substring str start (+ 1 end)) result)))
	    (if (zero? start)
		new-result
		(string-split-tr str (- start 1) new-result))))))
  (let ((result '())
    	(strlen (string-length str)))
    (if (zero? strlen)
	result
	(string-split-tr str (- strlen 1) result))))

; join list of strings by gap

(define (strings-join strings gap)
  (letrec ((ins (lambda (stuff)
		  (if (null? stuff)
		      '()
		      (cons gap (cons (car stuff) (ins (cdr stuff))))))))
    (if (pair? strings)
	(apply string-append (cdr (ins strings)))
	"")))

(define (string-split-lines str max)
  (let ((lines '())
	(end (string-length str)))
    (let loop ((start 0))
      (if (>= max (- end start))
	  (reverse! (cons (substring str start end) lines))
	  (let ((line-end (string-find-lastchar 
			   str #\space (+ start (min max (- end start))))))
	    (if (or (not line-end) (<= line-end start))
		(set! line-end (string-find-char str #\space start)))
	    (if (not line-end) (set! line-end end))
	    (set! lines (cons (substring str start line-end) lines))
	    (if (>= line-end end)
		(reverse! lines)
		(loop (+ line-end 1))))))))

; paragraph handling

(define fill-column 76)
(define fill-prefix "")

(define (fill-split-lines str)
  (string-split-lines str (- fill-column (string-length fill-prefix))))