Emacs Lisp 的自然顺序排序

3

有人在Emacs Lisp中实现了自然排序吗?我知道这不难写,但借鉴别人的工作会更容易。

(是的,我简直无法相信我刚刚搜索了一个Emacs函数,却找不到它。)

1个回答

4

这段代码提供了一个'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))))

这是我的测试:
(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")))

示例用法如下:

(sort '("b" "a" "1" "f19" "f" "f2" "f1can") 'dictionary-lessp)

产量
("1" "a" "b" "f" "f1can" "f2" "f19")

太棒了,谢谢!另外,我认为你在“p != 0”之前忘记加上“;;”了。 - Ken
我不明白你在说哪个检查,能否解释一下? - Trey Jackson
文本“p!= 0”看起来像是注释(并且在COND中没有意义),但它之前没有注释标记。 - Ken

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接