選択範囲の空白を削るEmacsコマンド

bookmarkletを登録するたびに、置換コマンドと手作業で毎回空白を削る作業をするのが不毛だったので、こんなコマンドを作ってみた。まだいろいろと不完全だけど、とりあえず動く。

(defun pack-whitespace-region (start end)
  (interactive "r")
  (save-excursion
    (save-restriction
      (narrow-to-region start end)
      (goto-char (point-min))
      (while (re-search-forward "\n *" nil t)
        (replace-match " "))
      (goto-char (point-min))
      (while (re-search-forward "\\(.\\) +\\(.\\)" nil t)
        (let ((pos (match-end 1))
              (b (match-string-no-properties 1))
              (a (match-string-no-properties 2)))
          (let ((s (if (and (save-match-data (string-match "[a-zA-Z0-9#%]" b))
                            (save-match-data (string-match "[a-zA-Z0-9#%]" a)))
                       " " "")))
            (replace-match (concat b s a)))
          (goto-char pos))))))

アルゴリズムをごく簡単に言えば、改行とインデントを空白1つに置換してから、単語の区切りとなる空白を残してそれ以外の空白を削除している。

既知のバグ

  • 文字列の中身まで処理してしまう
  • 単語を構成する文字の種類が決め打ち
  • コメントに未対応

真面目にやるならsyntax-tableを使った実装になるかな。