33.15 Сортировка текста

Функции сортировки, описанные в этом разделе, все переставляют текст в буфере. Это в отличие от функции sort, которая переупорядочивает элементы списка (см. Функции, переставляющие списки). Возвращаемые значения этих функций не имеют смысла.

Функция: sort-subr reverse nextrecfun endrecfun &optional startkeyfun endkeyfun predicate

Эта функция является общей подпрограммой сортировки текста, которая разбивает буфер на записи, а затем сортирует их. Большинство команд в этом разделе используют эту функцию.

Чтобы понять, как работает sort-subr, представьте, что вся доступная часть буфера разделена на непересекающиеся части, называемые записями сортировки. Записи могут быть как смежными, так и нет, но они не должны перекрываться. Часть каждой записи сортировки (возможно, вся она) обозначается как ключ сортировки. Сортировка переупорядочивает записи в порядке их ключей сортировки.

Обычно записи переупорядочиваются в порядке возрастания ключа сортировки. Если первый аргумент функции sort-subr, reverse, не равен nil, записи сортировки переупорядочиваются в порядке убывания ключа сортировки.

Следующие четыре аргумента sort-subr — это функции, которые вызываются для перемещения точки через запись сортировки. Они вызываются многократно из sort-subr.

  1. nextrecfun вызывается с точкой в конце записи. Эта функция перемещает точку в начало следующей записи. Предполагается, что первая запись начинается в позиции точки при вызове sort-subr. Поэтому обычно следует переместить точку в начало буфера перед вызовом sort-subr.

    Эта функция может указать, что больше нет записей для сортировки, оставив точку в конце буфера.

  2. endrecfun вызывается с точкой внутри записи. Она перемещает точку в конец записи.
  3. startkeyfun вызывается для перемещения точки от начала записи к началу ключа сортировки. Этот аргумент необязателен; если он опущен, вся запись является ключом сортировки. Если он передан, функция должна либо вернуть значение, не равное nil, для использования в качестве ключа сортировки, либо вернуть nil, чтобы указать, что ключ сортировки находится в буфере, начиная с точки. В последнем случае endkeyfun вызывается для определения конца ключа сортировки.
  4. endkeyfun вызывается для перемещения точки от начала ключа сортировки к его концу. Этот аргумент необязателен. Если startkeyfun возвращает 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 остаются без полезной позиции.

Пользовательская опция: sort-fold-case

Если эта переменная не равна nil, sort-subr и другие функции сортировки буфера игнорируют регистр при сравнении строк.

Команда: sort-regexp-fields reverse record-regexp key-regexp start end

Эта команда сортирует регион между start и end по алфавиту, как указано в record-regexp и key-regexp. Если reverse — отрицательное целое число, сортировка выполняется в обратном порядке.

Алфавитная сортировка означает, что два ключа сортировки сравниваются путём сравнения первых символов каждого, вторых символов каждого и так далее. Если найдено несовпадение, это означает, что ключи сортировки неравны; ключ, символ которого меньше в точке первого несовпадения, является меньшим ключом сортировки. Отдельные символы сравниваются в соответствии с их числовыми кодами символов в наборе символов Emacs.

Значение аргумента record-regexp определяет, как разделить буфер на записи сортировки. В конце каждой записи выполняется поиск по этому регулярному выражению, и текст, соответствующий ему, принимается за следующую запись. Например, регулярное выражение ‘^.+$’, которое соответствует строкам, содержащим хотя бы один символ, кроме новой строки, сделает каждую такую строку записью сортировки. См. Регулярные выражения для описания синтаксиса и значения регулярных выражений.

Значение аргумента key-regexp определяет, какая часть каждой записи является ключом сортировки. key-regexp может соответствовать всей записи или только её части. В последнем случае остальная часть записи не влияет на упорядоченный порядок записей, но переносится вместе с записью при её перемещении на новую позицию.

Аргумент key-regexp может ссылаться на текст, соответствующий подвыражению record-regexp, или может быть самостоятельным регулярным выражением.

Если key-regexp это:

‘\digit’

то ключом сортировки является текст, соответствующий ‘\(...\)’ группе с номером 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 в минибуфере.

Команда: sort-lines reverse start end

Эта команда сортирует по алфавиту строки в регионе между start и end. Если reverse не равен nil, сортировка выполняется в обратном порядке.

Команда: sort-paragraphs reverse start end

Эта команда сортирует по алфавиту абзацы в регионе между start и end. Если reverse не равен nil, сортировка выполняется в обратном порядке.

Команда: sort-pages reverse start end

Эта команда сортирует по алфавиту страницы в регионе между start и end. Если reverse не равен nil, сортировка выполняется в обратном порядке.

Команда: sort-fields field start end

Эта команда сортирует строки в регионе между start и end, сравнивая их по алфавиту по field-му полю каждой строки. Поля разделяются пробелами и нумеруются, начиная с 1. Если field отрицателен, сортировка выполняется по (−field)-му полю с конца строки. Эта команда полезна для сортировки таблиц.

Команда: sort-numeric-fields field start end

Эта команда сортирует строки в регионе между start и end, сравнивая их численно по field-му полю каждой строки. Поля разделяются пробелами и нумеруются, начиная с 1. Указанное поле должно содержать число в каждой строке региона. Числа, начинающиеся с 0, рассматриваются как восьмеричные, а числа, начинающиеся с ‘0x’, — как шестнадцатеричные.

Если field отрицателен, сортировка выполняется по (−field)-му полю с конца строки. Эта команда полезна для сортировки таблиц.

Пользовательская опция: sort-numeric-base

Эта переменная задаёт систему счисления по умолчанию для разбора чисел функцией sort-numeric-fields.

Команда: sort-columns reverse &optional beg end

Эта команда сортирует строки в регионе между beg и end, сравнивая их по алфавиту по определённому диапазону столбцов. Позиции столбцов beg и end ограничивают диапазон столбцов, по которым выполняется сортировка.

Если reverse не равен nil, сортировка выполняется в обратном порядке.

Одна необычная особенность этой команды заключается в том, что вся строка, содержащая позицию beg, и вся строка, содержащая позицию end, включаются в сортируемый регион.

Обратите внимание, что sort-columns отвергает текст, содержащий табуляции, потому что табуляции могут быть разделены указанными столбцами. Используйте M-x untabify для преобразования табуляций в пробелы перед сортировкой.

Когда это возможно, эта команда фактически работает путём вызова утилиты sort.