Функции сортировки, описанные в этом разделе, все переставляют текст в буфере. Это в отличие от функции sort, которая переупорядочивает элементы списка (см. Функции, переставляющие списки). Возвращаемые значения этих функций не имеют смысла.
Эта функция является общей подпрограммой сортировки текста, которая разбивает буфер на записи, а затем сортирует их. Большинство команд в этом разделе используют эту функцию.
Чтобы понять, как работает sort-subr, представьте, что вся доступная часть буфера разделена на непересекающиеся части, называемые записями сортировки. Записи могут быть как смежными, так и нет, но они не должны перекрываться. Часть каждой записи сортировки (возможно, вся она) обозначается как ключ сортировки. Сортировка переупорядочивает записи в порядке их ключей сортировки.
Обычно записи переупорядочиваются в порядке возрастания ключа сортировки. Если первый аргумент функции sort-subr, reverse, не равен nil, записи сортировки переупорядочиваются в порядке убывания ключа сортировки.
Следующие четыре аргумента sort-subr — это функции, которые вызываются для перемещения точки через запись сортировки. Они вызываются многократно из sort-subr.
sort-subr. Поэтому обычно следует переместить точку в начало буфера перед вызовом sort-subr.
Эта функция может указать, что больше нет записей для сортировки, оставив точку в конце буфера.
nil, для использования в качестве ключа сортировки, либо вернуть nil, чтобы указать, что ключ сортировки находится в буфере, начиная с точки. В последнем случае endkeyfun вызывается для определения конца ключа сортировки.
nil, а этот аргумент опущен (или равен nil), то ключ сортировки простирается до конца записи. Нет необходимости в endkeyfun, если startkeyfun возвращает значение, отличное от nil.
Аргумент predicate — это функция, используемая для сравнения ключей. Она вызывается с двумя аргументами — сравниваемыми ключами и должна возвращать не nil, если первый ключ должен идти перед вторым в порядке сортировки. То, что именно представляют собой аргументы ключей, зависит от того, что возвращают startkeyfun и endkeyfun. Если predicate опущен или равен nil, по умолчанию используется <, если ключи — числа, compare-buffer-substrings, если ключи — ячейки cons (чьи car и cdr являются начальной и конечной позициями ключа в буфере), и string< в противном случае (предполагается, что ключи — строки).
В качестве примера sort-subr приведём полное определение функции sort-lines:
;; Обратите внимание, что первые две строки строки документации ;; фактически являются одной строкой при просмотре пользователем. (defun sort-lines (reverse beg end) "Сортировать строки в регионе по алфавиту;\ аргумент означает обратный порядок. При вызове из программы есть три аргумента:
REVERSE (не-nil означает обратный порядок),\ BEG и END (регион для сортировки). Переменная `sort-fold-case' определяет,\ влияет ли регистр букв на порядок сортировки."
(interactive "P\nr")
(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)))))
Здесь forward-line перемещает точку в начало следующей записи, а end-of-line перемещает точку в конец записи. Мы не передаём аргументы startkeyfun и endkeyfun, потому что вся запись используется в качестве ключа сортировки.
Функция sort-paragraphs очень похожа, за исключением того, что её вызов sort-subr выглядит так:
(sort-subr reverse
(lambda ()
(while (and (not (eobp))
(looking-at paragraph-separate))
(forward-line 1)))
'forward-paragraph)
Маркеры, указывающие на какие-либо записи сортировки, после возврата sort-subr остаются без полезной позиции.
Если эта переменная не равна nil, sort-subr и другие функции сортировки буфера игнорируют регистр при сравнении строк.
Эта команда сортирует регион между start и end по алфавиту, как указано в record-regexp и key-regexp. Если reverse — отрицательное целое число, сортировка выполняется в обратном порядке.
Алфавитная сортировка означает, что два ключа сортировки сравниваются путём сравнения первых символов каждого, вторых символов каждого и так далее. Если найдено несовпадение, это означает, что ключи сортировки неравны; ключ, символ которого меньше в точке первого несовпадения, является меньшим ключом сортировки. Отдельные символы сравниваются в соответствии с их числовыми кодами символов в наборе символов Emacs.
Значение аргумента record-regexp определяет, как разделить буфер на записи сортировки. В конце каждой записи выполняется поиск по этому регулярному выражению, и текст, соответствующий ему, принимается за следующую запись. Например, регулярное выражение ‘^.+$’, которое соответствует строкам, содержащим хотя бы один символ, кроме новой строки, сделает каждую такую строку записью сортировки. См. Регулярные выражения для описания синтаксиса и значения регулярных выражений.
Значение аргумента key-regexp определяет, какая часть каждой записи является ключом сортировки. key-regexp может соответствовать всей записи или только её части. В последнем случае остальная часть записи не влияет на упорядоченный порядок записей, но переносится вместе с записью при её перемещении на новую позицию.
Аргумент key-regexp может ссылаться на текст, соответствующий подвыражению record-regexp, или может быть самостоятельным регулярным выражением.
Если key-regexp это:
то ключом сортировки является текст, соответствующий ‘\(...\)’ группе с номером digit в record-regexp.
то вся запись является ключом сортировки.
то sort-regexp-fields ищет совпадение с этим регулярным выражением внутри записи. Если такое совпадение найдено, оно становится ключом сортировки. Если совпадения с key-regexp внутри записи нет, то эта запись игнорируется, то есть её позиция в буфере не изменяется. (Другие записи могут перемещаться вокруг неё.)
Например, если вы планируете отсортировать все строки в регионе по первому слову в каждой строке, начинающемуся с буквы ‘f’, вам следует установить record-regexp в ‘^.*$’, а key-regexp в ‘\<f\w*\>’. Результирующее выражение выглядит так:
(sort-regexp-fields nil "^.*$" "\\<f\\w*\\>"
(region-beginning)
(region-end))
Если вы вызываете sort-regexp-fields интерактивно, она запрашивает record-regexp и key-regexp в минибуфере.
Эта команда сортирует по алфавиту строки в регионе между start и end. Если reverse не равен nil, сортировка выполняется в обратном порядке.
Эта команда сортирует по алфавиту абзацы в регионе между start и end. Если reverse не равен nil, сортировка выполняется в обратном порядке.
Эта команда сортирует по алфавиту страницы в регионе между start и end. Если reverse не равен nil, сортировка выполняется в обратном порядке.
Эта команда сортирует строки в регионе между start и end, сравнивая их по алфавиту по field-му полю каждой строки. Поля разделяются пробелами и нумеруются, начиная с 1. Если field отрицателен, сортировка выполняется по (−field)-му полю с конца строки. Эта команда полезна для сортировки таблиц.
Эта команда сортирует строки в регионе между start и end, сравнивая их численно по field-му полю каждой строки. Поля разделяются пробелами и нумеруются, начиная с 1. Указанное поле должно содержать число в каждой строке региона. Числа, начинающиеся с 0, рассматриваются как восьмеричные, а числа, начинающиеся с ‘0x’, — как шестнадцатеричные.
Если field отрицателен, сортировка выполняется по (−field)-му полю с конца строки. Эта команда полезна для сортировки таблиц.
Эта переменная задаёт систему счисления по умолчанию для разбора чисел функцией sort-numeric-fields.
Эта команда сортирует строки в регионе между beg и end, сравнивая их по алфавиту по определённому диапазону столбцов. Позиции столбцов beg и end ограничивают диапазон столбцов, по которым выполняется сортировка.
Если reverse не равен nil, сортировка выполняется в обратном порядке.
Одна необычная особенность этой команды заключается в том, что вся строка, содержащая позицию beg, и вся строка, содержащая позицию end, включаются в сортируемый регион.
Обратите внимание, что sort-columns отвергает текст, содержащий табуляции, потому что табуляции могут быть разделены указанными столбцами. Используйте M-x untabify для преобразования табуляций в пробелы перед сортировкой.
Когда это возможно, эта команда фактически работает путём вызова утилиты sort.