I use sort-lines fairly frequently to keep my #includes , uses or variable names in order. Occasionally though, I need to sort something slightly more complicated and I end up writing a little perl script. I found myself thinking it must be equally easy in emacs.

For example, I say I have the following data which I want to sort by the second field which is in position 12 and 13.

Edward Wood 9 01/07/2005 Ed Smith 25 06/12/2004 James Brown 18 01/07/2005 Jon James 13 05/15/2007

Now, emacs does have a sort-columns function which does all sorts of fancy things including checking if we are using Unix and shelling out to sort if possible, but it doesn’t seem to be able to do a numerical comparison. However, in sort.el it does have a general purpose sorting function called sort-subr .

( defun sort-subr (reverse nextrecfun endrecfun &optional startkeyfun endkeyfun predicate)

sort-lines itself is a good start for my custom function as it has all the code for handling regions, reversal and skipping between records (lines) that we need.

( defun sort-lines (reverse beg end) (interactive "P

r" ) ( save-excursion ( save-restriction (narrow-to-region beg end) (goto-char (point-min)) ( let ((inhibit-field-text-motion t)) (sort-subr reverse 'forward-line 'end-of-line)))))

Getting the startkeyfun and endkeyfun correct was fairly straight forward but I wasn’t entirely sure what information was passed to the predicate.

( defun sort-on-field (reverse beg end) (interactive "P

r" ) ( save-excursion ( save-restriction (narrow-to-region beg end) (goto-char (point-min)) ( let ((inhibit-field-text-motion t)) (sort-subr reverse 'forward-line 'end-of-line ( lambda () (forward-char 12)) ( lambda () (forward-char 2)) ( lambda (a b) (message (format "[%s] [%s]" a b)))))))) [(703 . 705)] [(676 . 678)] [(757 . 759)] [(730 . 732)] [(757 . 759)] [(703 . 705)] [(730 . 732)] [(703 . 705)]

The final working version:

( defun sort-on-field (reverse beg end) (interactive "P

r" ) ( save-excursion ( save-restriction (narrow-to-region beg end) (goto-char (point-min)) ( let ((inhibit-field-text-motion t)) (sort-subr reverse 'forward-line 'end-of-line ( lambda () (forward-char 12)) ( lambda () (forward-char 2)) ( lambda (a b) ( let ((s1 (buffer-substring (car a) (cdr a))) (s2 (buffer-substring (car b) (cdr b)))) (< (string-to-number s1) (string-to-number s2)))))))))

Providing a nice way of asking for the start and end location of the sorting field is left as an exercise for the reader.