3 ;; JSCL is free software: you can redistribute it and/or
4 ;; modify it under the terms of the GNU General Public License as
5 ;; published by the Free Software Foundation, either version 3 of the
6 ;; License, or (at your option) any later version.
8 ;; JSCL is distributed in the hope that it will be useful, but
9 ;; WITHOUT ANY WARRANTY; without even the implied warranty of
10 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 ;; General Public License for more details.
13 ;; You should have received a copy of the GNU General Public License
14 ;; along with JSCL. If not, see <http://www.gnu.org/licenses/>.
19 (defun string-length (string)
20 (storage-vector-size string))
22 (defun make-string (n &key initial-element)
23 (make-array n :element-type 'character :initial-element initial-element))
25 (defun char (string index)
26 (unless (stringp string) (error "~S is not a string" string))
27 (storage-vector-ref string index))
31 ((symbolp x) (symbol-name x))
32 (t (make-string 1 :initial-element x))))
34 (defun string= (s1 s2 &key (start1 0) end1 (start2 0) end2)
35 (let* ((s1 (string s1))
41 (when (= (- end2 start2) (- end1 start1))
42 (dotimes (i (- end2 start2) t)
43 (unless (char= (char s1 (+ start1 i)) (char s2 (+ start2 i)))
44 (return-from string= nil))))))
46 (defun string/= (s1 s2 &key (start1 0) end1 (start2 0) end2)
47 (let* ((s1 (string s1))
53 (dotimes (i (max (- end1 start1) (- end2 start2)) nil)
54 (when (or (>= (+ start1 i) n1)
56 (return-from string/= (+ start1 i)))
57 (unless (char= (char s1 (+ start1 i)) (char s2 (+ start2 i)))
58 (return-from string/= (+ start1 i))))))
61 (defun compare-strings (s1 s2 start1 end1 start2 end2 char-eq char-lt if-eq if-a-sub-b if-b-sub-a)
62 ;; step through strings S1 and S2, using bounds START1 END1 START2 END2.
63 ;; using character comparison functions CHAR-EQ (equality) and CHAR-LT (less-than),
64 ;; find the first difference, if any, and return its index.
65 ;; the IF-* params say what to do if the strings are equal, or a strict prefix substring of the other:
66 ;; if T, it returns the first different index. if NIL, it returns NIL.
67 (let* ((s1 (string s1))
69 (end1 (or end1 (length s1)))
70 (end2 (or end2 (length s2)))
71 (len-1 (- end1 start1))
72 (len-2 (- end2 start2)))
73 (dotimes (i (max len-1 len-2) (if if-eq (+ start1 i) nil))
74 (when (= i len-1) ;; ran off the end of s1
75 (return-from compare-strings (if if-a-sub-b (+ start1 i) nil)))
76 (when (= i len-2) ;; ran off the end of s2
77 (return-from compare-strings (if if-b-sub-a (+ start1 i) nil)))
78 (let ((c1 (char s1 (+ start1 i)))
79 (c2 (char s2 (+ start2 i))))
80 (when (not (funcall char-eq c1 c2)) ;; found a difference
81 (return-from compare-strings
82 (if (not (funcall char-lt c1 c2))
86 (defun string< (s1 s2 &key (start1 0) end1 (start2 0) end2)
87 (compare-strings s1 s2 start1 end1 start2 end2
91 (defun string> (s1 s2 &key (start1 0) end1 (start2 0) end2)
92 (compare-strings s1 s2 start1 end1 start2 end2
96 (defun string<= (s1 s2 &key (start1 0) end1 (start2 0) end2)
97 (compare-strings s1 s2 start1 end1 start2 end2
101 (defun string>= (s1 s2 &key (start1 0) end1 (start2 0) end2)
102 (compare-strings s1 s2 start1 end1 start2 end2
106 (define-setf-expander char (string index)
107 (let ((g!string (gensym))
110 (values (list g!string g!index)
113 `(aset ,g!string ,g!index ,g!value)
114 `(char ,g!string ,g!index))))
117 (defun concat (&rest strs)
118 (flet ((concat-two (str1 str2)
119 (concatenate-storage-vector str1 str2)))
120 (!reduce #'concat-two strs "")))
123 (defun string-upcase (string &key (start 0) end)
124 (let* ((string (string string))
125 (new (make-string (length string))))
126 (dotimes (i (length string) new)
128 (if (and (or (null start) (>= i start))
129 (or (null end) (< i end)))
130 (char-upcase (char string i))
133 (defun nstring-upcase (string &key (start 0) end)
134 (let ((end (or end (length string))))
135 (dotimes (i (- end start) string)
136 (aset string (+ start i)
137 (char-upcase (char string (+ start i)))))))
139 (defun string-downcase (string &key (start 0) end)
140 (let* ((string (string string))
141 (new (make-string (length string))))
142 (dotimes (i (length string) new)
144 (if (and (or (null start) (>= i start))
145 (or (null end) (< i end)))
146 (char-downcase (char string i))
149 (defun nstring-downcase (string &key (start 0) end)
150 (let ((end (or end (length string))))
151 (dotimes (i (- end start) string)
152 (aset string (+ start i)
153 (char-downcase (char string (+ start i)))))))
155 (defun string-capitalize (string &key (start 0) end)
156 (let* ((string (string string))
157 (new (make-string (length string)))
158 (just-saw-alphanum-p nil))
159 (dotimes (i (length string) new)
161 (cond ((or (and start (< i start))
165 (not just-saw-alphanum-p))
166 (char-upcase (char string i)))
168 (char-downcase (char string i)))))
169 (setq just-saw-alphanum-p (alphanumericp (char string i))))))
171 (defun nstring-capitalize (string &key (start 0) end)
172 (let ((end (or end (length string)))
173 (just-saw-alphanum-p nil))
174 (dotimes (i (- end start) string)
175 (aset string (+ start i)
177 (not just-saw-alphanum-p))
178 (char-upcase (char string (+ start i)))
179 (char-downcase (char string (+ start i)))))
180 (setq just-saw-alphanum-p (alphanumericp (char string (+ start i)))))))
182 (defun string-equal (s1 s2 &key start1 end1 start2 end2)
183 (let* ((s1 (string s1))
187 (start1 (or start1 0))
189 (start2 (or start2 0))
191 (when (= (- end2 start2) (- end1 start1))
192 (dotimes (i (- end2 start2) t)
193 (unless (char-equal (char s1 (+ start1 i)) (char s2 (+ start2 i)))
194 (return-from string-equal nil))))))
196 ;; just like string/= but with char-equal instead of char=
197 (defun string-not-equal (s1 s2 &key (start1 0) end1 (start2 0) end2)
198 (let* ((s1 (string s1))
204 (dotimes (i (max (- end1 start1) (- end2 start2)) nil)
205 (when (or (>= (+ start1 i) n1)
206 (>= (+ start2 i) n2))
207 (return-from string-not-equal (+ start1 i)))
208 (unless (char-equal (char s1 (+ start1 i)) (char s2 (+ start2 i)))
209 (return-from string-not-equal (+ start1 i))))))
211 (defun string-trim (character-bag string)
212 (string-left-trim character-bag (string-right-trim character-bag string)))
214 (defun string-left-trim (character-bag string)
215 (let* ((string (string string))
217 (start (or (position-if-not (lambda (c) (find c character-bag)) string) n)))
218 (subseq string start)))
220 (defun string-right-trim (character-bag string)
221 (let* ((string (string string))
224 (when (not (find (char string (- n i 1)) character-bag))
225 (return-from string-right-trim (subseq string 0 (- n i)))))))