2010年9月8日水曜日

[Emacs]Unicodeエスケープ文字を復元する

\u0040\u006b\u006f\u0073\u0068\u005f\u0062\u006f\u0074
上記のようなUnicodeエスケープ文字を元の文字列に戻すためのEmacs Lispです。ついでなので逆のエスケープする関数も書いておきます。

xyzzyの方は単純にElispのコードを書き換えただけ。xyzzyはemacsより書き方に幅があるようだけど、あんまりトリッキーなコードだとelisp<=>xyzzy間のコードの移植が大変になりそう。

;; #+:Emacs
(defun unicode-unescape-region (start end)
"指定した範囲のUnicodeエスケープ文字(\\uXXXX)をデコードする."
(interactive "*r")
(save-restriction
(narrow-to-region start end)
(goto-char (point-min))
(while (re-search-forward "\\\\u\\([[:xdigit:]]\\{4\\}\\)" nil t)
(replace-match (string (unicode-char
(string-to-number (match-string 1) 16)))
nil t))))
(defun unicode-escape-region (&optional start end)
"指定した範囲の文字をUnicodeエスケープする."
(interactive "*r")
(save-restriction
(narrow-to-region start end)
(goto-char (point-min))
(while (re-search-forward "." nil t)
(replace-match (format "\\u%04x"
(char-unicode
(char (match-string 0) 0)))
nil t))))
;; #+:Emacs
;; こちらも参照→ http://github.com/kosh04/emacs-lisp > xyzzy.el
(defun char-unicode (char) (encode-char char 'ucs))
(defun unicode-char (code) (decode-char 'ucs code))
;; #+:xyzzy
(defun unicode-unescape-region (&optional from to)
(interactive "*r")
(or (< from to)
(rotatef from to))
#+NIL
(save-excursion
(goto-char from)
(while (scan-buffer "\\\\u\\([A-Za-z0-9_]\\{4\\}\\)" :regexp t :limit to)
(let ((str (match-string 1)))
(delete-region (match-beginning 0) (match-end 0))
(insert (unicode-char (parse-integer str :radix 16))))))
(save-excursion
(save-restriction
(narrow-to-region from to)
(goto-char (point-min))
(while (re-search-forward "\\\\u\\([A-Za-z0-9_]\\{4\\}\\)" t)
(replace-match (string (unicode-char
(parse-integer (match-string 1) :radix 16)))
:literal t))))
)

emacsでこんな感じの置換操作を行う場合は以下のように書くのが定石らしい。

(while (re-search-forward "検索したい文字列" nil t)
  (replace-match "置換後の文字列" nil 'リテラルかどうか))

xyzzyならストリームを扱う関数を作ってed::text-decode-regionから呼び出すのが便利。

参考リンク