GNU Emacs 32.0.50 (9008bf64c3) のマニュアルを PLaMo 翻訳で機械翻訳したものです。誤訳を含むことがあります。原文: https://www.gnu.org/software/emacs/manual/html_node/elisp/Sorting.html ・ emacs-doc.conao3.com

33.15 テキストの並べ替え

本節で説明するソート関数は、いずれもバッファ内のテキストを並べ替えます。これは、リストの要素の順序を並べ替える関数 sort とは対照的です(リストを並べ替える関数 を参照)。これらの関数が返す値に意味はありません。

関数: sort-subr reverse nextrecfun endrecfun &optional startkeyfun endkeyfun predicate

この関数は、バッファをレコード単位に分割してソートを行う汎用的なテキストソートルーチンです。本セクションのコマンドの多くは、この関数を使用しています。

sort-subrの仕組みを理解するには、バッファのアクセス可能な領域全体を、ソートレコードと呼ばれる互いに重なり合わない断片に分割されていると考えてください。これらのレコードは連続している場合もあればそうでない場合もありますが、互いに重なってはなりません。各ソートレコードの一部(場合によってはその全部)がソートキーとして指定されます。ソート処理では、レコードがソートキーの順に並べ替えられます。

通常、レコードはソートキーの昇順に並べ替えられます。sort-subr 関数の第1引数 reverse が nil 以外の場合、ソート対象のレコードはソートキーの降順に並べ替えられます。

sort-subr に続く4つの引数は、ソートレコード内でポイントを移動させるために呼び出される関数です。これらは sort-subr 内部から何度も呼び出されます。

  1. nextrecfun は、レコードの末尾にポイントがある状態で呼び出されます。この関数は、ポイントを次のレコードの先頭に移動します。sort-subr が呼び出された時点で、最初のレコードはポイントの位置から始まっているとみなされます。したがって、通常は sort-subr を呼び出す前に、ポイントをバッファの先頭に移動させておく必要があります。

    この関数は、バッファの末尾にポインタを置くことで、ソート対象のレコードがもうないことを示せます。

  2. endrecfun はレコード内で point と共に呼び出されます。これにより、point がレコードの末尾に移動します。
  3. startkeyfun は、ポインタをレコードの先頭からソートキーの先頭へ移動させるために呼び出されます。この引数は省略可能であり、省略した場合はレコード全体がソートキーとなります。指定された場合、関数はソートキーとして使用する非 nil 値を返すか、あるいはソートキーがポインタから始まるバッファ内にあることを示すために nil を返す必要があります。後者の場合、ソートキーの終端を特定するために endkeyfun が呼び出されます。
  4. endkeyfun は、ソートキーの先頭から末尾までポイントを移動させるために呼び出されます。この引数は省略可能です。startkeyfun が nil を返し、かつこの引数が省略された(または nil が指定された)場合、ソートキーはレコードの末尾まで及びます。startkeyfun が nil 以外の値を返す場合、endkeyfun は不要です。

引数 predicate は、キーを比較するために使用する関数です。比較対象のキーという2つの引数で呼び出され、ソート順において最初のキーが2番目のキーより前に来るべき場合は non-nil を返す必要があります。キーの引数が具体的に何になるかは、startkeyfun と endkeyfun が何を返すかによって決まります。predicate が省略されているか、あるいは nil である場合、キーが数値であれば < に、キーがコンスセル(その car と cdr がキーの開始および終了バッファ位置となるもの)であれば compare-buffer-substrings に、それ以外の場合(キーが文字列であると想定される場合)は string< にデフォルトで設定されます。

sort-subr の例として、sort-lines の完全な関数定義を以下に示します。

;; Note that the first two lines of doc string
;; are effectively one line when viewed by a user.
(defun sort-lines (reverse beg end)
  "Sort lines in region alphabetically;\
 argument means descending order.
Called from a program, there are three arguments:
REVERSE (non-nil means reverse order),\
 BEG and END (region to sort).
The variable `sort-fold-case' determines\
 whether alphabetic case affects
the sort order."
  (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 が負の整数の場合、ソートは逆順で行われます。

アルファベット順のソートとは、2つのソートキーの先頭文字、2番目の文字というように順に比較することを指します。不一致が見つかった場合、それらのソートキーは等しくないことを意味し、最初に不一致が生じた箇所の文字が小さい方のソートキーが、より小さいソートキーとなります。個々の文字は、Emacs文字セットにおける数値文字コードに基づいて比較されます。

record-regexp 引数の値は、バッファをソートレコードにどのように分割するかを指定します。各レコードの末尾でこの正規表現による検索が行われ、それに一致するテキストが次のレコードとして取り込まれます。例えば、改行以外の文字を少なくとも1つ含む行に一致する正規表現 ‘^.+$’ を使用すると、そのような各行がソートレコードになります。正規表現の構文と意味については、正規表現を参照してください。

key-regexp 引数の値で、各レコードのどの部分がソートキーになるかを指定します。key-regexp はレコード全体、あるいはその一部に一致することがあります。後者の場合、レコードの残りの部分はソート順に影響を与えませんが、レコードが新しい位置に移動する際にそのまま引き継がれます。

key-regexp 引数は、record-regexp の部分式にマッチしたテキストを参照することも、それ自体が正規表現であることもできます。

key-regexp が:

‘\digit’

このとき、record-regexpにおけるdigit番目の‘\(...\)’括弧グループに一致するテキストがソートキーとなります。

‘\&’

すると、レコード全体がソートキーになります。

正規表現

次に 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 で始まる数値は 8 進数として、‘0x’ で始まる数値は 16 進数として扱われます。

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 ユーティリティプログラムを呼び出すことで動作します。