git.fiddlerwoaroof.com
Browse code

Add more string utilities

Ed Langley authored on 13/04/2019 23:16:00
Showing 4 changed files
... ...
@@ -39,7 +39,10 @@
39 39
   :license "MIT"
40 40
   :depends-on (#:should-test)
41 41
   :components ((:file "string-utils/package")
42
-               (:file "string-utils/string-utils" :depends-on ("string-utils/package"))
42
+               (:file "string-utils/split"
43
+                :depends-on ("string-utils/package"))
44
+               (:file "string-utils/string-utils"
45
+                :depends-on ("string-utils/package"))
43 46
                #-lispworks
44 47
                (:file "string-utils/test" :depends-on ("string-utils/string-utils"))))
45 48
 
... ...
@@ -2,5 +2,8 @@
2 2
 
3 3
 (defpackage :fwoar.string-utils
4 4
   (:use :cl)
5
-  (:export #:get-part-modifier #:split))
5
+  (:export #:get-part-modifier
6
+           #:split
7
+           #:insert-at
8
+           #:insert-where))
6 9
 
7 10
new file mode 100644
... ...
@@ -0,0 +1,177 @@
1
+(in-package :fwoar.string-utils)
2
+
3
+(deftype array-length ()
4
+  `(integer 0 ,array-dimension-limit))
5
+(deftype array-index ()
6
+  `(integer 0 ,(1- array-dimension-limit)))
7
+
8
+(defun get-part-modifier (char string &optional count)
9
+  (declare (optimize #+dev (debug 3) #-dev (speed 3))
10
+           (type character char)
11
+           (type string string))
12
+
13
+  (flet ((count-splits (string)
14
+           (declare (optimize (speed 3))
15
+                    (type simple-string string))
16
+           (do* ((x (the array-length 0) (1+ x))
17
+                 (cur-char #1=(aref string x) #1#)
18
+                 (result (the array-length 0) (if (char= cur-char char)
19
+                                                  (1+ result)
20
+                                                  result)))
21
+                ((= x (1- (length string))) (1+ result))
22
+             (declare (type array-length result)))))
23
+    (typecase string
24
+      ((and string (not simple-string))
25
+       (setf string (copy-seq string))))
26
+    (unless count
27
+      (setf count (count-splits string))))
28
+
29
+  (let ((parts (make-array count :initial-element nil :element-type '(or string null)))
30
+        (start-idx 0)
31
+        (target-spot 0))
32
+    (prog1 parts
33
+      (dotimes (end-idx (length string))
34
+        (when (typecase string
35
+                (simple-string (char= (aref string end-idx) char))
36
+                (string (char= (aref string end-idx) char)))
37
+          (setf (aref parts target-spot)
38
+                (make-array (- end-idx start-idx) :displaced-to string :displaced-index-offset start-idx
39
+                            :element-type 'character))
40
+          (incf target-spot)
41
+          (setf start-idx (1+ end-idx))
42
+          (when (= target-spot (1- count))
43
+            (return))))
44
+      (when (<= start-idx (length string))
45
+        (setf (aref parts target-spot)
46
+              (make-array (- (length string) start-idx)
47
+                          :displaced-to string :displaced-index-offset start-idx
48
+                          :element-type 'character))))))
49
+
50
+;; TODO: implement test
51
+(defun %split-on-char (divider string &key count (test nil))
52
+  (declare (optimize #+dev (debug 3) #+dev (speed 0) #+dev (space 0)
53
+                     #-dev (speed 3) #-dev(space 2))
54
+           (type (or null array-length) count)
55
+           (type (or null function symbol) test)
56
+           (type character divider)
57
+           (type string string))
58
+  (typecase string
59
+    ((and string (not simple-string))
60
+     (setf string (copy-seq string))))
61
+  (check-type string simple-string)
62
+
63
+  (flet ((count-splits (string)
64
+           (declare (optimize #+dev (debug 3) #+dev (speed 0) #+dev (space 0)
65
+                              #-dev (speed 3) #-dev(space 2))
66
+                    (type simple-string string))
67
+           (if (/= 0 (length string))
68
+               (do* ((x (the array-length 0) (1+ x))
69
+                     (cur-char #1=(aref string x) #1#)
70
+                     (result (the array-length
71
+                                  (if (char= cur-char divider)
72
+                                      1
73
+                                      0))
74
+                             (if (char= cur-char divider)
75
+                                 (1+ result)
76
+                                 result)))
77
+                    ((= x (1- (length string))) (1+ result))
78
+                 (declare (type array-length result)))
79
+               0))
80
+         (find-pos (start-pos)
81
+           (declare (optimize #+dev (debug 3) #+dev (speed 0) #+dev (space 0)
82
+                     #-dev (speed 3) #-dev(space 2))
83
+                    (type array-index start-pos))
84
+           (etypecase test
85
+             (function (position divider string :start start-pos :test test))
86
+             (null (position divider string :start start-pos))
87
+             (symbol (position divider string :start start-pos :test (symbol-function test))))))
88
+
89
+    (unless count
90
+      (setf count (count-splits string)))
91
+
92
+    (check-type count array-length)
93
+    (let ((parts (make-array (max count 1) :fill-pointer 0))
94
+          (start-pos (the fixnum 0)))
95
+      (declare (dynamic-extent start-pos))
96
+      (prog1 parts
97
+        (loop 
98
+           for end-pos = (find-pos start-pos)
99
+           while end-pos 
100
+           do
101
+             (vector-push (subseq string start-pos end-pos) parts)
102
+             (setf start-pos (1+ end-pos))
103
+           while (< (length parts) (1- count))
104
+           finally
105
+             (cond ((or (and end-pos count)
106
+                        (< start-pos (length string)))
107
+                    (vector-push (subseq string start-pos)
108
+                                 parts))
109
+                   ((not end-pos)
110
+                    (vector-push "" parts))))))))
111
+
112
+(defun %split-on-string (divider string &key count (test nil))
113
+  (declare (optimize #+dev (debug 3) (speed 3))
114
+           (type string divider string)
115
+           (type (or null function symbol) test)
116
+           (type (or null array-index) count))
117
+  (flet ((%search (start-pos)
118
+           (declare (optimize (speed 3))
119
+                    (type array-index start-pos)
120
+                    (inline))
121
+           (typecase divider
122
+             (simple-string (typecase string
123
+                              (simple-string (search divider string :start2 start-pos))
124
+                              (string (search divider string :start2 start-pos))))
125
+             (string (search divider string :start2 start-pos))))
126
+         (%search-with-test (start-pos test)
127
+           (declare (optimize (speed 3))
128
+                    (type array-index start-pos)
129
+                    (type function test)
130
+                    (inline))
131
+           (typecase divider
132
+             (simple-string (typecase string
133
+                              (simple-string (search divider string :start2 start-pos :test test))
134
+                              (string (search divider string :start2 start-pos :test test))))
135
+             (string (search divider string :start2 start-pos :test test)))))
136
+    (declare (dynamic-extent (function %search)
137
+                             (function %search-with-test)))
138
+    (let ((num-parts (the array-length 0))
139
+          (pattern-length (the array-length (length divider)))
140
+          (search-test (typecase test
141
+                         (function test)
142
+                         (null)
143
+                         (symbol (symbol-function test))))
144
+          (parts (make-array (if count count 100)
145
+                             :adjustable t
146
+                             :fill-pointer 0))
147
+          (start-pos 0))
148
+      (loop 
149
+         for end-pos = (typecase search-test
150
+                         (function (%search-with-test start-pos search-test))
151
+                         (null (%search start-pos)))
152
+         do
153
+           (vector-push-extend (subseq string start-pos end-pos) parts) 
154
+           (incf (the array-length num-parts))
155
+         while end-pos
156
+         do (setf start-pos (the array-length (+ pattern-length end-pos)))
157
+         until (and count (>= (1+ num-parts) count))
158
+         finally
159
+           (when (and count end-pos)
160
+             (vector-push-extend (subseq string (+ pattern-length end-pos)) parts))
161
+           (return parts)))))
162
+
163
+(defun split (divider string &key count (test nil) (type nil type-p))
164
+  (declare (optimize #+dev (debug 3) (speed 3) (space 3)))
165
+  (unless test
166
+    (setf test
167
+          (typecase divider
168
+            (string 'equal)
169
+            (t 'eql))))
170
+  (let ((result (etypecase divider
171
+                  (character (%split-on-char divider string :count count :test test))
172
+                  (string (if (= 1 (length divider))
173
+                              (%split-on-char (aref divider 0) string :count count :test test)
174
+                              (%split-on-string divider string :count count :test test))))))
175
+    (if type-p
176
+        (coerce result type)
177
+        result)))
... ...
@@ -1,177 +1,12 @@
1 1
 (in-package :fwoar.string-utils)
2 2
 
3
-(deftype array-length ()
4
-  `(integer 0 ,array-dimension-limit))
5
-(deftype array-index ()
6
-  `(integer 0 ,(1- array-dimension-limit)))
7
-
8
-(defun get-part-modifier (char string &optional count)
9
-  (declare (optimize #+dev (debug 3) #-dev (speed 3))
10
-           (type character char)
11
-           (type string string))
12
-
13
-  (flet ((count-splits (string)
14
-           (declare (optimize (speed 3))
15
-                    (type simple-string string))
16
-           (do* ((x (the array-length 0) (1+ x))
17
-                 (cur-char #1=(aref string x) #1#)
18
-                 (result (the array-length 0) (if (char= cur-char char)
19
-                                                  (1+ result)
20
-                                                  result)))
21
-                ((= x (1- (length string))) (1+ result))
22
-             (declare (type array-length result)))))
23
-    (typecase string
24
-      ((and string (not simple-string))
25
-       (setf string (copy-seq string))))
26
-    (unless count
27
-      (setf count (count-splits string))))
28
-
29
-  (let ((parts (make-array count :initial-element nil :element-type '(or string null)))
30
-        (start-idx 0)
31
-        (target-spot 0))
32
-    (prog1 parts
33
-      (dotimes (end-idx (length string))
34
-        (when (typecase string
35
-                (simple-string (char= (aref string end-idx) char))
36
-                (string (char= (aref string end-idx) char)))
37
-          (setf (aref parts target-spot)
38
-                (make-array (- end-idx start-idx) :displaced-to string :displaced-index-offset start-idx
39
-                            :element-type 'character))
40
-          (incf target-spot)
41
-          (setf start-idx (1+ end-idx))
42
-          (when (= target-spot (1- count))
43
-            (return))))
44
-      (when (<= start-idx (length string))
45
-        (setf (aref parts target-spot)
46
-              (make-array (- (length string) start-idx)
47
-                          :displaced-to string :displaced-index-offset start-idx
48
-                          :element-type 'character))))))
49
-
50
-;; TODO: implement test
51
-(defun %split-on-char (divider string &key count (test nil))
52
-  (declare (optimize #+dev (debug 3) #+dev (speed 0) #+dev (space 0)
53
-                     #-dev (speed 3) #-dev(space 2))
54
-           (type (or null array-length) count)
55
-           (type (or null function symbol) test)
56
-           (type character divider)
57
-           (type string string))
58
-  (typecase string
59
-    ((and string (not simple-string))
60
-     (setf string (copy-seq string))))
61
-  (check-type string simple-string)
62
-
63
-  (flet ((count-splits (string)
64
-           (declare (optimize #+dev (debug 3) #+dev (speed 0) #+dev (space 0)
65
-                              #-dev (speed 3) #-dev(space 2))
66
-                    (type simple-string string))
67
-           (if (/= 0 (length string))
68
-               (do* ((x (the array-length 0) (1+ x))
69
-                     (cur-char #1=(aref string x) #1#)
70
-                     (result (the array-length
71
-                                  (if (char= cur-char divider)
72
-                                      1
73
-                                      0))
74
-                             (if (char= cur-char divider)
75
-                                 (1+ result)
76
-                                 result)))
77
-                    ((= x (1- (length string))) (1+ result))
78
-                 (declare (type array-length result)))
79
-               0))
80
-         (find-pos (start-pos)
81
-           (declare (optimize #+dev (debug 3) #+dev (speed 0) #+dev (space 0)
82
-                     #-dev (speed 3) #-dev(space 2))
83
-                    (type array-index start-pos))
84
-           (etypecase test
85
-             (function (position divider string :start start-pos :test test))
86
-             (null (position divider string :start start-pos))
87
-             (symbol (position divider string :start start-pos :test (symbol-function test))))))
88
-
89
-    (unless count
90
-      (setf count (count-splits string)))
91
-
92
-    (check-type count array-length)
93
-    (let ((parts (make-array (max count 1) :fill-pointer 0))
94
-          (start-pos (the fixnum 0)))
95
-      (declare (dynamic-extent start-pos))
96
-      (prog1 parts
97
-        (loop 
98
-           for end-pos = (find-pos start-pos)
99
-           while end-pos 
100
-           do
101
-             (vector-push (subseq string start-pos end-pos) parts)
102
-             (setf start-pos (1+ end-pos))
103
-           while (< (length parts) (1- count))
104
-           finally
105
-             (cond ((or (and end-pos count)
106
-                        (< start-pos (length string)))
107
-                    (vector-push (subseq string start-pos)
108
-                                 parts))
109
-                   ((not end-pos)
110
-                    (vector-push "" parts))))))))
111
-
112
-(defun %split-on-string (divider string &key count (test nil))
113
-  (declare (optimize #+dev (debug 3) (speed 3))
114
-           (type string divider string)
115
-           (type (or null function symbol) test)
116
-           (type (or null array-index) count))
117
-  (flet ((%search (start-pos)
118
-           (declare (optimize (speed 3))
119
-                    (type array-index start-pos)
120
-                    (inline))
121
-           (typecase divider
122
-             (simple-string (typecase string
123
-                              (simple-string (search divider string :start2 start-pos))
124
-                              (string (search divider string :start2 start-pos))))
125
-             (string (search divider string :start2 start-pos))))
126
-         (%search-with-test (start-pos test)
127
-           (declare (optimize (speed 3))
128
-                    (type array-index start-pos)
129
-                    (type function test)
130
-                    (inline))
131
-           (typecase divider
132
-             (simple-string (typecase string
133
-                              (simple-string (search divider string :start2 start-pos :test test))
134
-                              (string (search divider string :start2 start-pos :test test))))
135
-             (string (search divider string :start2 start-pos :test test)))))
136
-    (declare (dynamic-extent (function %search)
137
-                             (function %search-with-test)))
138
-    (let ((num-parts (the array-length 0))
139
-          (pattern-length (the array-length (length divider)))
140
-          (search-test (typecase test
141
-                         (function test)
142
-                         (null)
143
-                         (symbol (symbol-function test))))
144
-          (parts (make-array (if count count 100)
145
-                             :adjustable t
146
-                             :fill-pointer 0))
147
-          (start-pos 0))
148
-      (loop 
149
-         for end-pos = (typecase search-test
150
-                         (function (%search-with-test start-pos search-test))
151
-                         (null (%search start-pos)))
152
-         do
153
-           (vector-push-extend (subseq string start-pos end-pos) parts) 
154
-           (incf (the array-length num-parts))
155
-         while end-pos
156
-         do (setf start-pos (the array-length (+ pattern-length end-pos)))
157
-         until (and count (>= (1+ num-parts) count))
158
-         finally
159
-           (when (and count end-pos)
160
-             (vector-push-extend (subseq string (+ pattern-length end-pos)) parts))
161
-           (return parts)))))
162
-
163
-(defun split (divider string &key count (test nil) (type nil type-p))
164
-  (declare (optimize #+dev (debug 3) (speed 3) (space 3)))
165
-  (unless test
166
-    (setf test
167
-          (typecase divider
168
-            (string 'equal)
169
-            (t 'eql))))
170
-  (let ((result (etypecase divider
171
-                  (character (%split-on-char divider string :count count :test test))
172
-                  (string (if (= 1 (length divider))
173
-                              (%split-on-char (aref divider 0) string :count count :test test)
174
-                              (%split-on-string divider string :count count :test test))))))
175
-    (if type-p
176
-        (coerce result type)
177
-        result)))
3
+(defun insert-at (position item string)
4
+  (concatenate 'string
5
+               (subseq string 0 position)
6
+               (string item)
7
+               (subseq string position)))
8
+
9
+(defun insert-where (predicate item string)
10
+  (insert-at (position-if predicate string)
11
+             item
12
+             string))