-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlexical-compare.lisp
79 lines (68 loc) · 2.13 KB
/
lexical-compare.lisp
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
(defpackage :fwoar.lexical-compare
(:use :cl )
(:export
#:lexi-compare
#:apply-when
#:natural-sort-strings))
(in-package :fwoar.lexical-compare)
(defun parse-mixed-string (str)
(let ((first-int-pos (position-if #'digit-char-p str)))
(if (> (length str) 0)
(if first-int-pos
(if (> first-int-pos 0)
(cons (subseq str 0 first-int-pos)
(parse-mixed-string (subseq str first-int-pos)))
(multiple-value-bind (int end) (parse-integer str :junk-allowed t)
(cons int
(parse-mixed-string
(subseq str end)))))
(list str))
nil)))
(defgeneric part< (a b)
(:method (a b)
nil)
(:method ((a string) (b number))
t)
(:method ((a number) (b number))
(< a b))
(:method ((a string) (b string))
(string< a b)))
(defgeneric part= (a b)
(:method (a b)
nil)
(:method ((a number) (b number))
(= a b))
(:method ((a string) (b string))
(string= a b)))
#+(or)
(st:deftest test-parse-mixed-string ()
(st:should be equal
(list)
(parse-mixed-string ""))
(st:should be equal
(list "asdf")
(parse-mixed-string "asdf"))
(st:should be equal
(list "asdf" 1234)
(parse-mixed-string "asdf1234"))
(st:should be equal
(list 1234 "asdf")
(parse-mixed-string "1234asdf"))
(st:should be equal
(list "asdf" 1234 "a")
(parse-mixed-string "asdf1234a")))
(defun apply-when (fun &rest args)
(when (car (last args))
(apply 'apply fun args)))
(defun lexi-compare (a b &optional (elem-compare 'part<))
(let* ((mismatch-pos (mismatch a b :test 'part=))
(a-tail (when mismatch-pos (nthcdr mismatch-pos a)))
(b-tail (when mismatch-pos (nthcdr mismatch-pos b))))
(or (when (and a-tail b-tail)
(funcall elem-compare
(car a-tail)
(car b-tail)))
(null a-tail))))
(defun natural-sort-strings (a b)
(lexi-compare (parse-mixed-string a)
(parse-mixed-string b)))