単語数を数える

選択範囲の単語数、文字数、行数、などをMeadowで数えたい場合があります。Shell経由でwcコマンドに文字列を渡して計算してもらい、結果を受けとって表示する、という方法もあるらしいですが、環境依存になってしまうので却下。

そこでEmacs Lispだけでやる方法を探すと、ありました。出典は失念しましたが、とりあえずコードを。これを.emacsに追加すればいいです。

(defun word-count-region-jp (beg end) ;リージョンを指定して、 M-x my-mojisuu とする。
  (interactive "r")    ;リージョンの最初と最後の位置が beg と end に入る。
  (save-excursion
    (save-restriction
      (narrow-to-region beg end) ;編集可能領域をリージョンに制限する。
      (let (ch ch-id (ch-count 0))
        (goto-char (point-min))         ;バッファの先頭へ
        (while (not (eobp))             ;バッファの最後でない間、
          (setq ch (following-char))    ;現在位置の文字を ch に代入
          (setq ch-id (nth 0 (split-char ch))) ;その文字の leading-charcter
          (if (eq 'japanese-jisx0208 ch-id) ;その文字が JIS x 0208 ならば
              (setq ch-count (1+ ch-count))) ;カウンタ ch-count に 1 を足す。
          (if (eq 'katakana-jisx0201 ch-id) ;その文字が半角仮名でも
              (setq ch-count (1+ ch-count))) ;カウンタ ch-count に 1 を足す。
          (forward-char 1))             ;次の文字へ進む。
        (message "文字数は%d" ch-count) ;結果表示。
        ))))

(defun word-count-region-en (start end)
  (interactive "r")
  (save-excursion
    (save-restriction
      (let ((c 0) (l 0) (w 0) (in-word nil) c-after)
        (goto-char start)
        (while (< (point) end)
          (setq c-after (char-after (point))) ; no need (point) if emacs 20
          (if (= c-after ?\n)
              (setq l (1+ l)))
          (if (or (= c-after ?\n) (= c-after ? ) (= c-after ?\C-i))
              (if in-word
                  (setq w (1+ w) in-word nil))
            (setq c (1+ c) in-word t))
          (forward-char))
        (message (format "%d lines, %d words, %d characters" l w c))))))

これで、「word-count-region-jp」と「word-count-region-en」という関数が定義されます。「word-count-region-jp」の方は文字数だけ、「word-count-region-えn」は文字数、行数、単語数が表示されます。

僕は、このふたつの関数にショートカット「Ctrl+x Ctrl+j」と「Ctrl+x Ctrl+e」を割り当ててます。こんな感じ。

(global-set-key "\C-x\C-e" 'word-count-region-en)
(global-set-key "\C-x\C-j" 'word-count-region-jp)

便利便利。