正規表現で指定したファイルの文字コードを一括変換

emacsでファイルの文字コードを一括変換する方法は「http://www.bookshelf.jp/soft/meadow_25.html#SEC277」に先例があるが、いちいちdired で操作するのも面倒くさいので、正規表現でファイルを指定するものを用意した。
需要は低いだろな。

利用法

  1. M-x change-regexp-specified-file-coding-system
  2. 次の順番で尋ねてくるので、適宜答える
    1. 対象ディレクトリ名
    2. 対象ファイルの正規表現
      • 例えば".txt"な拡張子のファイルをすべて変換したいのであれば、「\.txt$」と答えればヨロシ。
    3. 変換前ファイルのバックアップを取るかどうか

注意

  • 動作はMeadowでのみ確認
  • 対象ファイルをemacsで開くときに、文字コードを指定しなくても(変換前の)ファイルが正しい文字コードで開ける場合のみを想定しており、例えばemacsで読み込んだ(find-file)あとにrevert-buffer-with-coding-system をやらないと正しく開けないようなファイルの場合は正しく変換されない
    • そんな破壊的な操作を含むので、事前にバックアップをとれるようにしたのであります。
  • バックアップを取るときに、bkupディレクトリ内に同名ファイルがある場合、そのファイルは新しいもので上書きされる。

Emacs Lispコード

.emacs に書く。

;=======================================================================
; 特定のファイルの文字コードを一括して変更する
;
;=======================================================================


(defun my-interactive-directory-query ()
  ;; moccur-grep-find を参考にした
  (let ((dir default-directory))
    (setq dir
          (if (and (boundp 'running-xemacs) running-xemacs)
              (read-directory-name "target directory: " dir)
            (read-file-name "target directory: " nil nil t)))
    (if (and (file-exists-p dir)
             (file-directory-p  dir))
        (setq dir (file-name-as-directory dir))
      (setq dir (file-name-as-directory (file-name-directory dir)))
      (if (and (file-exists-p dir)
               (file-directory-p  dir))
          ()
        (error (format "No such directory %s" dir))
        (sleep-for 1)
        (setq dir nil)))
    dir))

(defun change-regexp-spcified-file-coding-system (dir regexp coding-system do-bkup)
  "指定したディレクトリ内の、正規表現に該当するファイルの文字コードを変換する。
ただし文字コードを指定しなくても変換前のファイルが正しい文字コードで開ける場合のみを想定しており、これ以外の場合の動作は保証しない。"
  (interactive
   (list (my-interactive-directory-query)
	  (read-string "Filename Regexp: ")
	  (read-coding-system "New Coding System: ")
	  (y-or-n-p "Backup original?: ")))
  (let* (target-files (bkup-dir nil))
    (setq target-files
	  (directory-files dir nil regexp nil))
    (if do-bkup
	(progn
	  (setq bkup-dir (concat dir "bkup"))
	  (if (not				; in case the directory doesnt exist.
	       (and (file-exists-p bkup-dir)
		    (file-directory-p bkup-dir)))
	      (make-directory bkup-dir))
	  ))

    (let ((work-list target-files) work-buffer (counter 0) target-file-path)
      (while work-list
	(setq target-file-path (concat (expand-file-name dir) (car work-list)))
	(setq work-buffer
	      (find-file-noselect target-file-path))
	(if do-bkup
	    (copy-file target-file-path
		       (concat bkup-dir "/" (car work-list)) t t))
	(set-buffer work-buffer)
	(set-buffer-file-coding-system coding-system)
	(save-buffer)
	(kill-buffer work-buffer)
	(setq counter (1+ counter))
	(setq file-name-history (cdr file-name-history)) ;; ファイル名履歴をクリーンに保つ
	(setq work-list (cdr work-list))
	)
      (message (concat (int-to-string counter) " files converted."))
      )
    ))