git.fiddlerwoaroof.com
Browse code

Add beginnings of routines to natural sort strings

Ed Langley authored on 09/06/2018 06:30:25
Showing 2 changed files
... ...
@@ -18,6 +18,7 @@
18 18
                #-lispworks #:should-test)
19 19
   :components ((:file "package")
20 20
                (:file "fwoar.lisputils")
21
+               (:file "lexical-compare")
21 22
                (:file "hash-functions")
22 23
                (:file "multiple-values")
23 24
                (:file "clos-helpers")
24 25
new file mode 100644
... ...
@@ -0,0 +1,70 @@
1
+(defpackage :fwoar.lexical-compare
2
+  (:use :cl )
3
+  (:export ))
4
+(in-package :fwoar.lexical-compare)
5
+
6
+(defun parse-mixed-string (str)
7
+  (let ((first-int-pos (position-if #'digit-char-p str)))
8
+    (if (> (length str) 0)
9
+        (if first-int-pos
10
+            (if (> first-int-pos 0)
11
+                (cons (subseq str 0 first-int-pos)
12
+                      (parse-mixed-string (subseq str first-int-pos)))
13
+                (multiple-value-bind (int end) (parse-integer str :junk-allowed t)
14
+                  (cons int
15
+                        (parse-mixed-string
16
+                         (subseq str end)))))
17
+            (list str))
18
+        nil)))
19
+
20
+(defgeneric part< (a b)
21
+  (:method (a b)
22
+    nil)
23
+  (:method ((a string) (b number))
24
+    t)
25
+  (:method ((a number) (b number))
26
+    (< a b))
27
+  (:method ((a string) (b string))
28
+    (string< a b)))
29
+
30
+(defgeneric part= (a b)
31
+  (:method (a b)
32
+    nil)
33
+  (:method ((a number) (b number))
34
+    (= a b))
35
+  (:method ((a string) (b string))
36
+    (string= a b)))
37
+
38
+(defun apply-when (fun &rest args)
39
+  (when (car (last args))
40
+    (apply 'apply fun args)))
41
+
42
+(defun lexi-compare (a b)
43
+  (apply-when 'part<
44
+              (car
45
+               (serapeum:drop-while (serapeum:op (apply 'part= _1))
46
+                                    (mapcar 'list a b)))))
47
+(st:deftest test-parse-mixed-string ()
48
+  (st:should be equal
49
+             (list)
50
+             (parse-mixed-string ""))
51
+
52
+  (st:should be equal
53
+             (list "asdf")
54
+             (parse-mixed-string "asdf"))
55
+
56
+  (st:should be equal
57
+             (list "asdf" 1234)
58
+             (parse-mixed-string "asdf1234"))
59
+
60
+  (st:should be equal
61
+             (list 1234 "asdf")
62
+             (parse-mixed-string "1234asdf"))
63
+
64
+  (st:should be equal
65
+             (list "asdf" 1234 "a")
66
+             (parse-mixed-string "asdf1234a")))
67
+
68
+(defun natural-sort-strings (a b)
69
+  (lexi-compare (parse-mixed-string a)
70
+                (parse-mixed-string b)))