UNICODE アンエスケープする
以下の環境で動作確認しました。
- Windows XP Home Edition SP3
- xyzzy 0.2.2.235
文字列を UNICODE アンエスケープします。
*unescape-unicode-string-default-regexp* は、デフォルトのアンエスケープする文字列にマッチする正規表現です。後述する *unescape-unicode-string-regexp-alist* で、正規表現を決定できなかった場合に使用されます。この変数には、以下の要素からなるリストをセットします。
正規表現は大文字小文字を区別します。大文字小文字を区別しないときは、関数 compile-regexp の第 2 引数に、t を指定してコンパイルした正規表現をセットしてください。
*unescape-unicode-string-regexp-alist* は、正規表現の連想リストで、関数と *unescape-unicode-string-default-regexp* と同様のリストのペアをセットします。先頭の要素から関数を実行し、関数が non-nil を返した要素の正規表現を使用します。
以下の正規表現が定義済みです。
- html-mode,
- //www1.odn.ne.jp/ymtz/html_plus-mode.html">html+-mode, xml-mode のマイナーモード XHTML1.0/1.1:『\(?:\([0-9]+\)\|x\([0-9a-f]+\)\);』(大文字小文字を区別しない)
- //www.geocities.jp/kiaswebsite/xyzzy/jscript-mode.html" title="kia's website - xyzzy関連 - jscript-mode.l">jscript-mode:『\\u\([0-9A-F]\{4\}\)』
- デフォルト
- 『%u\([0-9A-F]\{4\}\)』
コード
;; 文字列を UNICODE アンエスケープする ; デフォルトの正規表現 ; 第 1 要素にアンエスケープする文字列にマッチする正規表現 ; 第 2 要素以降に取り出す数値のグループ番号と基数をペアにしたコンスセル ; 正規表現は大文字小文字を区別する ; 大文字小文字を区別しないようにするには compile-regexp の第 2 引数に t を指定 ; してコンパイルした正規表現をセットする (defvar *unescape-unicode-string-default-regexp* `(,(compile-regexp "%u\\([0-9A-F]\\{4\\}\\)") (1 . 16))) ; 正規表現の連想リスト ; car の関数が non-nil を返すとき cdr の正規表現を使用する (defvar *unescape-unicode-string-regexp-alist* `((,#'(lambda () (or (member buffer-mode '("html-mode" "html+-mode") :test #'string=) (and (string= buffer-mode "xml-mode") (string-match "^xml:XHTML1\\.\\(?:0-\\(?:Strict\\|Frameset\\|Transitional\\)\\|1\\)$" mode-name)))) . (,(compile-regexp "&#\\(?:\\([0-9]+\\)\\|x\\([0-9a-f]+\\)\\);" t) (1 . 10) (2 . 16))) (,#'(lambda () (string= buffer-mode "jscript-mode")) . (,(compile-regexp "\\\\u\\([0-9A-F]\\{4\\}\\)") (1 . 16))) )) (defun unescape-unicode-string (str) (let* ((lst (or (some #'(lambda (x) (if (funcall (car x)) (cdr x))) *unescape-unicode-string-regexp-alist*) *unescape-unicode-string-default-regexp*)) (re (car lst)) (alst (cdr lst)) (getc (if (= (list-length alst) 1) (let ((n (caar alst)) (r (cdar alst))) #'(lambda () (parse-integer (match-string n) :radix r))) (let ((pint #'(lambda (x) (let ((str (match-string (car x)))) (if str (parse-integer str :radix (cdr x))))))) #'(lambda () (some pint alst))))) (tmpb (create-new-buffer " *work*")) code) (set-buffer tmpb) (unwind-protect (progn (insert str) (goto-char (point-min)) (while (scan-buffer re :tail t :regexp t) (when (setq code (funcall getc)) (delete-region (match-beginning 0) (match-end 0)) (insert (format nil "~C" (unicode-char code))))) (buffer-substring (point-min) (point-max))) (if tmpb (delete-buffer tmpb))))) ; リージョンを UNICODE アンエスケープする (defun unescape-unicode-string-region (from to) (interactive "*r") (let ((str (unescape-unicode-string (buffer-substring from to)))) (delete-region from to) (insert str))) ; セレクションを UNICODE アンエスケープする (defun unescape-unicode-string-selection () (interactive "*") (case (get-selection-type) ((1 2) (ed::map-selection #'(lambda (start end) (unescape-unicode-string-region start end)))) (3 (error "セレクションが矩形選択です")) (t (error "セレクションがありません"))))