« MacBook Pro 13-inch Mid 2010上でWindows 8 | トップページ | AppleScriptでPerl正規表現置換 »

2013年3月27日 (水)

AppleScriptでテキストを簡単に読み込む[更新]

Apple Script でテキストファイルを読み込む場合、open だとか read だとかを使う普通のやり方だと読み込みに失敗する確率がかなり高い(苦笑)。

そこで、できるだけ確実に読み込むために、do shell script 命令を使ってシェルコマンドで以下のようにして読み込んでいた。

 set text_contents to do shell script "cat < " & quoted form of file_path

ところが、最近、過去に書いた Apple Script を修正しているうちに、Apple Script で書き出したテキストファイルは、末尾の改行が消える場合があることに気づいた。

当初はどこに原因があるのかわからず、非常に困惑したが、検証の結果、どうやら、do shell script で読み込まれたテキストの末尾に改行がついている場合、Apple Script の変数に格納した時点で末尾の改行が消えてしまうことがわかった。

ウェブ上に掲載されている Apple 社提供の資料をあたってみると、それは do shell script 命令の仕様であり、回避するには、do shell script 〜 without altering line endings と書けばよいと明記されていた。

なので、do shell script で簡単にテキストを読み込むには、

 set text_contents to do shell script "cat < " & quoted form of file_path without altering line endings

と書くのが妥当だろう。

この方法で読み込めるテキストファイルは、文字コードが UTF-8 もしくは Shift JIS のみ、変数 text_contents に格納された時点で UTF-8 に自動変換される(ちなみに、EUC-JP のテキストを読み込むと、文字化けした UTF-8 に変換されてしまうので注意)。

一方、読み込むファイルの改行コードは、LF でも CR でも CRLF でもよく、デフォルト(without altering line endings を付けない状態)では変数に格納された時点でれば CR に自動変換される。なので、Apple Script 内で引き続き文字列置換などの処理を行う際は、改行コードが CR (¥r)だという前提でスクリプトを書く必要がある。それに対して without altering line endings を付けた場合、改行コードは変換されない。

つまり、without altering line endings は「文末の改行を消さない」「改行コードを変換しない」という二つの機能を併せ持っているになる。どちらか一方だけの機能を使うことはできない。

without altering line endings を付けた場合、Apple Script 内で引き続き文字列置換などの処理を行う際は、読み込んだテキストの改行コードが何なのか、留意する必要がある。

しかし、改行コードが何なのか不明のテキストを Apple Script に読み込んで処理したいという場合もあるだろう。そのような場合は、当然、Apple Script 内で改行コードを統一して処理しなければならない。

そんな時は敢えて、without altering line endings を付けないようにすることで、CR に統一することができる。だが、そうしてしまうと、今度は文末の改行が消えてしまう(苦笑)。

そこで、do shell script 内で一行 Perl コマンドを使って

 set text_contents to do shell script "perl -pe 's/(\r)\n/$1/g; s/\n/\r/g;' < " & quoted form of file_path without altering line endings

と書く方法を考えてみた。

一行 Perl (perl -e) では、標準入力から受け取ったデータは <STDIN> に格納されるが、これは一行ごとに配列になっている。-p というオプションを付けて「perl -pe」と書くことで、一行ごとに処理を行って print を行う。

Apple Script の do shell script 命令はそれらすべての行の出力結果をまとめて変数に渡す仕様のため、text_contents にはすべての改行が CR 置換されて格納される。

<STDIN> は省略して <> と書くことができ、また、変数 $_ は省略が可能である。省略せずに書き下すと以下のようになる。

while (<STDIN>) {
	$_ =~ s/(\r)\n/$1/g;
	$_ =~ s/\n/\r/g;
	print $_;
}

-p オプションにより「while (<STDIN>) { }」と「print $_;」を省略して書くことができるのである。


余談だが、上記のようにして読み込まれたテキストを、逆にファイルに書き出す際、

 do shell script "/bin/echo -n " & quoted form of text_contents & " | iconv -f utf-8 -t SHIFT_JIS | tr \"\r\" \"\n\" > " & quoted form of new_file_path

のように、iconv コマンドで文字コードの変換を、tr コマンドで改行コードの変換を行った上で書き出している。


(2013/03/29:更新)

« MacBook Pro 13-inch Mid 2010上でWindows 8 | トップページ | AppleScriptでPerl正規表現置換 »