Carbon emacsには、emacsから applescriptを実行する関数として
do-applescript
というのがある。とても便利なのだが、applescript
に文字列リテラルを渡す時のエスケープ処理が面倒なので、
専用の関数
applescript-string-literal
を作ってみることにした。
つまり、
(do-applescript "display dialog \"any-string\"")
の赤色の部分を作成する関数だ。
(do-applescript (format "display dialog %s" (applescript-string-literal "any-string")))のように使う。
最初は、単にバックスラッシュ使って、
ダブルクォートとバックスラッシュ自身をエスケープするだけでいいと思っていたのだが、
leopardの文字列処理はそう甘くはなかった。
どこが甘くなかったのか.....
例えば、
(do-applescript "display dialog \"Hello\"")
はちゃんと、Helloというメッセージダイアログを表示するのだが、
Helloを、"Hello" にかえて、
(do-applescript "display dialog \"\\\"Hello\\\"\"")
を実行すると、何故かエラーになってしまう。 バックスラッシュ(\)によるダブルクォート(")
のエスケープ処理が効いていないみたいだ。これは、バックスラッシュと円記号
にまつわるややこしい問題なのかと思い、試しに
(do-applescript "display dialog \"Hello\\\"")
を実行。すると、
Hello\ ではなく、
Hello¥ と表示された。スクリプトエディターで、\と¥のコードを確認すると、
ASCII NUMBER "\\" は 128、
ASCII NUMBER "¥" は 92
と評価される。(実際には¥はoption-\で入力)ASCII NUMBER "¥" は 92
ということは、 do-applescriptで送るバックスラッシュコード(asciiの92)
が、applescript では半角の¥記号と認識され、
それで文字列リテラルのエスケープが効かないのか?
確かに、applescriptの ascii character 128 を使って、
(do-applescript "display dialog \"Hello\" & ascii character 128")
を実行すれば、正しく
Hello\
と表示される。
めんどくさいけど、
バックスラッシュを ascii character 128 に、
ダブルクォートを ascii character 34
にして、それらと文字列リテラルを & でくっつければいいらしい。
でも、以前は確かこんな症状は起きなかったような気がする。
僕自身が何か変な環境設定でも行ったのだろうか....
調べてみると、環境変数 __CF_USER_TEXT_ENCODING
が関係していることがわかった。この環境変数を UTFエンコードを表す 0x08000100
に設定して、
(例 : export __CF_USER_TEXT_ENCODING=`printf 0x%X $UID`":0x08000100:14")
emacsを再起動すると、
(do-applescript "display dialog \"\\\"Hello\\\"\"")
も正常に動作し、これまでの問題は全て解決する。しかし今度は日本語が化けてしまう。
デフォルトの
$UID:1:14では shift_jisでエンコードすれば問題なかったのに......結局、 __CF_USER_TEXT_ENCODING が ShiftJisの場合は、文字列リテラルと
ascii character 文の結合で処理し、
それ以外の場合は単純なエスケープ処理を施すように
applescript-string-literal 関数を実装することにした。
applescript-string-literalソースコード
(cond ((and (<= emacs-major-version 22) (string-match ".*:1:14" (format "%s" (getenv "__CF_USER_TEXT_ENCODING")))) ;; emacs22 and CFUserTextEncodingが MacJapanese の場合 (defun applescript-string-literal (str) "do-applescriptに渡す文字列リテラルを作成\n\ バックスラッシュとダブルクォーテーションをそれぞれ\n\ ascii character 128 と ascii character 34に変換\n\ ex. (applescript-string-literal \"\\\"abc\\\"\")\n\ => \"ascii character 34 & \\\"abc\\\" & ascii character 34\"" (let ((reslst '())) (mapc '(lambda (ch) (cond ((= ch ?\\) (setq reslst (cons 128 reslst))) ((= ch ?\") (setq reslst (cons 34 reslst))) ((consp (car reslst)) (setcar reslst (cons ch (car reslst)))) (t (setq reslst (cons (list ch) reslst))))) str ;; (append str nil) ) (if (null reslst) "\"\"" (mapconcat '(lambda (x) (if (consp x) (concat "\"" (reverse x) "\"") (format "ascii character %d" x)) ) (reverse reslst) " & ")) ))) (t ;; emacs23 or CFUserTextEncodingが MacJapanese 以外 の場合 (defun applescript-string-literal (str) "do-applescriptに渡す文字列リテラルを作成" (concat "\"" (replace-regexp-in-string ;; convert " => \" "\\\"" "\\\\\"" (replace-regexp-in-string ;; convert \ => \\ "\\\\" "\\\\\\\\" str)) "\""))))
この applescript-string-literal を使って、
(do-applescript (format "display dialog %s" (applescript-string-literal "Hello \"backslash\"-\\")))を実行すると、めでたく Hello "backslash"-\ が表示される。
__CF_USER_TEXT_ENCODINGがデフォルトのShiftJisの状態なら、
日本語だって、
(do-applescript (format "display dialog %s" (encode-coding-string (applescript-string-literal "バックスラッシュ \"\\\"を表示") 'shift_jis)))ちゃんと バックスラッシュ"\"を表示 のダイアログが表示される。
.... でも、本当は何かもっとスマートな方法があるんだろなあ....
追記 (2009年 11月4日 水曜日)
cocoa emacs (emacs23.1) の場合は、ascii characterへの変換は必要なく、
日本語もエンコードせずにそのまま送ればいいようだ。
0 件のコメント:
コメントを投稿