Emacs Lisp 的自然顺序排序

Ken*_*Ken 4 emacs elisp natural-sort

有人在 Emacs Lisp 中实现了自然顺序排序吗?我知道写起来并不难,但是借用别人的作品更容易。

(是的,我不敢相信我刚刚搜索了 Emacs 函数却找不到它。)

Tre*_*son 6

该代码提供了一个'dictionary-lessp可用于排序算法。到目前为止,似乎在我的测试中有效:

(defun dictionary-lessp (str1 str2)
  "return t if STR1 is < STR2 when doing a dictionary compare
(splitting the string at numbers and doing numeric compare with them)"
  (let ((str1-components (dict-split str1))
        (str2-components (dict-split str2)))
    (dict-lessp str1-components str2-components)))

(defun dict-lessp (slist1 slist2)
  "compare the two lists of strings & numbers"
  (cond ((null slist1)
         (not (null slist2)))
        ((null slist2)
         nil)
        ((and (numberp (car slist1))
              (stringp (car slist2)))
         t)
        ((and (numberp (car slist2))
              (stringp (car slist1)))
         nil)
        ((and (numberp (car slist1))
              (numberp (car slist2)))
         (or (< (car slist1) (car slist2))
             (and (= (car slist1) (car slist2))
                  (dict-lessp (cdr slist1) (cdr slist2)))))
        (t
         (or (string-lessp (car slist1) (car slist2))
             (and (string-equal (car slist1) (car slist2))
                  (dict-lessp (cdr slist1) (cdr slist2)))))))

(defun dict-split (str)
  "split a string into a list of number and non-number components"
  (save-match-data 
    (let ((res nil))
      (while (and str (not (string-equal "" str)))
        (let ((p (string-match "[0-9]*\\.?[0-9]+" str)))
          (cond ((null p)
                 (setq res (cons str res))
                 (setq str nil))
                ((= p 0)
                 (setq res (cons (string-to-number (match-string 0 str)) res))
                 (setq str (substring str (match-end 0))))
                (t
                 (setq res (cons (substring str 0 (match-beginning 0)) res))
                 (setq str (substring str (match-beginning 0)))))))
      (reverse res))))
Run Code Online (Sandbox Code Playgroud)

这是我的测试:

(and (dictionary-lessp "a" "b")
     (null (dictionary-lessp "b" "a"))
     (null (dictionary-lessp "a" "a"))
     (dictionary-lessp "1" "2")
     (null (dictionary-lessp "2" "1"))
     (null (dictionary-lessp "1" "1"))
     (dictionary-lessp "1" "a")
     (null (dictionary-lessp "a" "1"))
     (dictionary-lessp "" "a")
     (null (dictionary-lessp "a" ""))

     (dictionary-lessp "ab12" "ab34")
     (dictionary-lessp "ab12" "ab123")
     (dictionary-lessp "ab12" "ab12d")
     (dictionary-lessp "ab132" "ab132z")


     (dictionary-lessp "132zzzzz" "ab132z")
     (null (dictionary-lessp "1.32" "1ab")))
Run Code Online (Sandbox Code Playgroud)

用法示例是:

(sort '("b" "a" "1" "f19" "f" "f2" "f1can") 'dictionary-lessp)
Run Code Online (Sandbox Code Playgroud)

产量

("1" "a" "b" "f" "f1can" "f2" "f19")
Run Code Online (Sandbox Code Playgroud)