windowsのファイル名ソートっぽいの

数字の大きさ順に並ぶとかいうアレ。一般的な名称は知らない。実装してる関数も知らないので書いた。

(defun filename< (p1 p2)
  (while (and (not (equal p1 ""))
              (not (equal p2 "")))
    (let* ((a (string-match "[0-9]+" p1))
           (m1 (match-string 0))
           (b (string-match "[0-9]+" p2))
           (m2 (match-string 0)))
      (if (string= p1 p2 :end1 a :end2 b)
          (let ((i1 (if m1 (parse-integer m1) -1))
                (i2 (if m2 (parse-integer m2) -1)))
            (if (not (= i1 i2))
                (return (< i1 i2))))
        (return (string< p1 p2 :end1 a :end2 b)))
      (setq p1 (if a (substring p1 (length m1)) "")
            p2 (if b (substring p2 (length m2)) "")))))

(stable-sort '("9" "0002" "1203" "i3") 'filename<)
|
("0002" "9" "1203" "i3")

(stable-sort '("000" "001" "00A" "00B" "010" "011" "01A") 'filename<)
|
("000" "00A" "00B" "001" "01A" "010" "011")

下の例みたいのがあるから、一般的に便利とは言えない。この関数なら:radixを指定してやれば切り替えられるのだが、string-matchも変更する必要があるので面倒。今回は省略した。