次: , 前: Auto Filling, 上: Text


31.15 テキストのソート

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

— 機能: sort-subr reverse nextrecfun endrecfun &optional startkeyfun endkeyfun

この関数は、バッファ内のテキストをレコードに分割してソートする 汎用のテキストソートルーティンである。 本節のコマンドのほとんどは、この関数を用いる。

sort-subrの動作方法を理解するためは、 バッファの参照可能部分全体が ソートレコード(sort record)と呼ばれる 重なり合いのない断片に分割されていると考える。 レコードは連続しているかもしれないし、そうでないかもしれないが、 けっして重なり合わない。 各ソートレコードの一部分(あるいは全体)をソートキーとして区別する。 ソートでは、ソートキーの順に並ぶようにレコードを並び替える。

通常、レコードをソートキーの昇順に並べ替える。 関数sort-subrの第1引数reversenil以外であると、 ソートキーの降順にレコードを並べ替える。

sort-subrのつぎの4つの引数は、 ソートレコードをまたいでポイントを移動するために呼ばれる関数である。 それらは、sort-subrで多数回呼び出される。

  1. nextrecfunは、レコードの末尾にポイントを置いて呼び出される。 この関数は、つぎのレコードの先頭にポイントを移動する。 最初のレコードの先頭は、 sort-subrを呼び出したときのポイント位置であると仮定する。 したがって、sort-subrを呼び出すまえには、普通、 バッファの先頭にポイントを移動しておくこと。

    この関数は、バッファの末尾にポイントを置いておくことで、 ソートレコードがなくなったことを表せる。

  2. endrecfunは、レコード内にポイントを置いて呼び出される。 レコードの末尾にポイントを移動する。
  3. startkeyfunは、レコードの先頭からソートキーの先頭へ ポイントを移動するために呼び出される。 この引数は省略可能であり、省略するとレコード全体をソートキーとする。 指定した場合、その関数は、ソートキーとして用いるnil以外の値を返すか、 バッファのポイント位置からソートキーが始まることを表すnilを返すこと。 後者の場合、ソートキーの末尾を探すためにendkeyfunが呼ばれる。
  4. endkeyfunは、ソートキーの先頭からソートキーの末尾に ポイントを移動するために呼び出される。 この引数は省略可能である。 startkeyfunnilを返しこの引数が省略されている (あるいはnilである)と、ソートキーはレコードの末尾までである。 startkeyfunnil以外の値を返すのであれば、 endkeyfunは必要ない。

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

          
          
          ;; 説明文字列の始めの2行は、ユーザーが見るときには
          ;; 実質的には1行であることに注意
          (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))
                (sort-subr reverse 'forward-line 'end-of-line))))
     

ここで、forward-lineはつぎのレコードの先頭にポイントを移動し、 end-of-lineはレコードの末尾にポイントを移動する。 レコード全体をソートキーとして用いるため、 引数startkeyfunendkeyfunは指定しない。

関数sort-paragraphsもほぼ同様であるが、 つぎのようにsort-subrを呼び出す点が異なる。

          (sort-subr reverse
                     (function
                       (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

このコマンドは、startendのあいだの領域を record-regexpkey-regexpの指定に従って アルファベット順にソートする。 reverseが負の整数であると、逆順にソートする。

アルファベット順のソートとは、 最初の文字同士、2番目の文字同士といった具合に 2つのソートキーを比較することである。 不一致がみつかると、ソートキーが等しくないことを意味し、 最初の不一致箇所の文字が小さいほうのソートキーが小さい。 個々の文字は、Emacsの文字集合における文字コードの数値に従って比較する。

引数record-regexpの値は、バッファをソートレコードに 分割する方法を指定する。 各レコードの末尾において、この正規表現を探索し それに一致したテキストをつぎのレコードとする。 たとえば、正規表現`^.+$'は、 少なくとも1つの文字のあとに改行があるような行に一致し、 そのような行をソートレコードとする。 正規表現の構文と意味については、see Regular Expressions

引数key-regexpの値は、 レコードのどの部分がソートキーであるかを指定する。 key-regexpは、レコード全体かその一部分に一致する。 後者の場合、レコードの残りの部分は、レコードの並び替え順序には影響しないが、 レコードをその新たな位置に移動するときにいっしょに移動される。

引数key-regexprecord-regexpの部分式に一致したテキストを参照してもよいし、 独立した正規表現でもよい。

key-regexpにはつぎの可能性がある。

`\digit'
record-regexpdigit番目の 括弧によるグループ化`\(...\)'に一致したテキストがソートキーである。
`\&'
レコード全体がソートキーである。
正規表現
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-regexpkey-regexpを問い合わせる。

— コマンド: sort-lines reverse start end

このコマンドは、startendのあいだの領域の行を アルファベット順にソートする。 reversenil以外であると、逆順にソートする。

— コマンド: sort-paragraphs reverse start end

このコマンドは、startendのあいだの領域の段落を アルファベット順にソートする。 reversenil以外であると、逆順にソートする。

— コマンド: sort-pages reverse start end

このコマンドは、startendのあいだの領域のページを アルファベット順にソートする。 reversenil以外であると、逆順にソートする。

— コマンド: sort-fields field start end

このコマンドは、startendのあいだの領域の行を 各行のfield番目のフィールド同士をアルファベット順に比較してソートする。 フィールドは白文字で区切られ、1から数える。 fieldが負であると、 行末から−field番目のフィールドでソートする。 このコマンドは、表をソートするのに有用である。

— コマンド: sort-numeric-fields field start end

このコマンドは、startendのあいだの領域の行を 各行のfield番目のフィールド同士を数値として比較してソートする。 領域内の各行の指定したフィールドには数があること。 フィールドは白文字で区切られ、1から数える。 fieldが負であると、 行末から−field番目のフィールドでソートする。 このコマンドは、表をソートするのに有用である。

— コマンド: sort-columns reverse &optional beg end

このコマンドは、startendのあいだの領域の行を 特定範囲のコラムをアルファベット順に比較してソートする。 begendのコラム位置は、ソート対象のコラムの範囲を区切る。

reversenil以外であると、逆順にソートする。

このコマンドの普通でない点は、 位置begを含む行全体と位置endを含む行全体も ソート対象の領域に含まれることである。

sort-columnsは、ユーティリティプログラムsortを使うため、 タブ文字を含むテキストを正しく扱えない。 ソートするまえにM-x untabifyを使ってタブを空白に変換すること。