このページは福井県立大学の田中求之が2006年1月まで運用していた Mac のサーバ運用に関する会議室 「Web Scripter's Meeting」の記録です。情報が古くなっている可能性がありますのでご注意ください。

Perl 5.8.1におけるエスケープ文字の扱いについて

発言者:後藤潔
( Date Monday, October 04, 2004 13:36:15 )


MacJPerl 5.2.0r4 J2で書いたスクリプトをPerl 5.8.1に移植しようとしているのですが,MacJPerl で動作していた正規表現が動作しない場合があります。Perl 5.8.1における正規表現の方法,特に
エスケープ文字の扱い方について教えていただきたく投稿しています。
環境:MacOSX 10.3.5
Perlバージョン:5.8.1
スクリプト記述文字コード:UTF8
テキストファイル文字コード:UTF8
問題点:正規表現の中で半角スラッシュ「/」を「\」でエスケープできない。
試験中のスクリプトは次の通りです。cgiプログラムとして使用したとき,「500 Internal Server 
Error」というメッセージがでますが,置換は行われています。ただし,変換後のファイル
「regtestnew.txt」は,テキストエディタmi 2.1.5で普通に開けず,文字コードをUTF8にして,
再読込する必要がありました。コメントアウトしている二つの正規表現は,いずれもMacJPerlでは
使用できていたsyntaxです。Perl 5.8.1では使用できませんでした。
Apacheのエラーログには次のように記載されています。
[Sun Oct  3 23:07:33 2004] [error] [client 127.0.0.1] Premature end of script headers: 
/Library/WebServer/CGI-Executables/testEncode05.cgi
スクリプトをどのように修正したらいいでしょうか。ご教示願えると幸いです。

=====スクリプト開始

#!/usr/local/bin/perl 
#Script is written in UTF-8.
use utf8;
$infile = "temp/regtest.txt";
$outfile = "temp/regtestnew.txt";
open my $in, "<:utf8", $infile or die;
open my $out, ">:utf8", $outfile or die;
while(<$in>){
  tr/.,/。、/;
  tr/A-Za-z0-9%/A-Za-z0-9%/;
  s/+/+/g;
  s/‐/-/g;
#  s/W\/0型/W\/O型/g;
#  s///\//g;
  print $out $_;
}
close my $in;
close my $out;

=====スクリプト終了

perl さんからのコメント
( Monday, October 04, 2004 13:51:40 )

s!...!!g;の様に別の文字で書けませんか。

しあわせのツボ さんからのコメント
( Monday, October 04, 2004 14:36:06 )

MacJapaneseで半角\を(半角¥と区別して)書くと、
U+005cでなくU+0080にマップされます。
ファイルをUTF-8で作っても、アプリの内部処理がMacJapaneseの場合、
実装によってどちらにマップされるかが異なります。
そして、miは正に内部処理がMacJapaneseのアプリです。
U+0080にマップされた場合、それはエスケープ文字ではありませんから、
正しく動作しなくなります。

テキストエディットやJedit Xなど内部処理がUnicodeのエディタで開いて、
U+0080をU+005cに置換すると、直るかもしれません。

後藤潔 さんからのコメント
( Tuesday, October 05, 2004 13:56:31 )

perlさん,コメントありがとうございます。
アドバイスいただいた方法でエスケープ文字を回避することができました。

しあわせのツボさん,コメントありがとうございます。
半角\と半角¥が区別できていませんでした。スクリプトを書くエディタをJeditにして,
半角\をコピー・ペーストすることでエスケープ文字が使えるようになりました。
私のキーボードはASCII配列ですが,半角英字モードにしてバックスラッシュキー(半角\)
を押しても半角¥になってしまいます。キーボードから直接バックスラッシュキー(半角\)
を入力する方法はあるでしょうか?

さて,エスケープ文字が使用できるようになり,置換も行われていますが,相変わらず「500 Internal Server Error」というメッセージがでています。ログのエラーメッセージも変わりません。
[Tue Oct  5 09:55:58 2004] [error] [client 127.0.0.1] Premature end of script headers: 
/Library/WebServer/CGI-Executables/testEncode07.cgi
ログのエラーメッセージも変わりません。エスケープ文字とは違う原因で,エラーが残っているようです。

しあわせのツボ さんからのコメント
( Tuesday, October 05, 2004 15:20:29 )

なるほど、見当がつきました。
はじめから、正規表現の問題ではなかったようです。

スクリプトの改行コードがCRのままではありませんか?
LFで保存し直してください。

# \はoption-¥で出ると思います。

後藤潔 さんからのコメント
( Tuesday, October 05, 2004 19:20:39 )

しあわせのツボさん,コメントありがとうございます。
改行コードはCRではなくLFになっていると思います。スクリプトをJeditで保存するときに
文字コード(UTF8)と改行コード(LF)を確認しています。
エスケープ文字に関しては,アドバイスいただいたおかげで,たとえば次のような正規表現
を記述できるようになりました。
  s/(\d)( ?)ml/$1 mL/g;
予め変換結果を書き込むファイル(regtestnew.txt)を用意しておいて,コンソールから
  perl testEncode07.cgi
を実行すると,UTFで保存しておいたファイル(regtest.txt)の中身が期待通りに変換され
て,regtestnew.txtに書き込まれています。上記の正規表現も期待通りの変換結果が得られ
ています。ちなみに,改行コードをLFではなく,CRにすると,スクリプトはコンソールから
も動作しないようです。
同じスクリプトをブラウザ上でcgiとして実行させると,ファイルには期待通りの変換結果が
書き込まれています。ということで,スクリプト中のエスケープ文字だけでなく,スクリプト
そのものも処理されていると判断しました。
正規表現による変換は期待通りに動作しているようですが,ブラウザには
500 Internal Server Error
というメッセージが表示され,エラーログには
Premature end of script headers: 
/Library/WebServer/CGI-Executables/testEncode07.cgi
と残っているのが現状です。
Premature end of script headers: に関して,Web上で検索してみましたが,解決策を見い
だすところまでいきませんでした。
perlスクリプトとしてではなく,cgiとして動作させたいと思いますので,ぜひ解決したいとこ
ろです。投稿時のタイトルからはずれてしまいましたが,ご教示いただければ幸いです。

しあわせのツボ さんからのコメント
( Tuesday, October 05, 2004 20:07:32 )

Perlスクリプトとしては正常に動作しているのですね。
だとすると…
ちゃんとブラウザに向けた出力を書いていますか?
処理が正常に終わったとしても、何らかの返答を返してあげないと
webサーバは「処理結果が戻って来ない>処理は未完了」と判断し
エラーを出します。
(使う人間も、本当に処理されたか不安ですし…)
print "Content-type: text/plain\n\ntask completed."; くらいで構わないので
何か足してみてください。

後藤潔 さんからのコメント
( Wednesday, October 06, 2004 08:18:39 )

しあわせのツボさん,コメントありがとうございます。
大変わかりやすい説明をありがとうございました。文字コード,正規表現,ファイルの入出力に
気をとられていました。ご教示いただいたとおり,ブラウザに向けた出力を書くことで解決いた
しました。そこで,MacJPerlで書いた正規表現をPerl 5.8.1に移植しました。その結果,
おそらくスクリプトの内部コードの違いによると思われる,手直しが必要な部分が出てきました。
たとえば,行頭あるいはタブ区切りの後で,ひらがな・漢字の前の一桁の数字を全角に直すという
スクリプトです。
s/(^|\t)1([あ-ヶ〜亜-熙])/${1}1$2/g;
漢字のコード範囲としてshift_jisでは[亜-熙]を指定していたのですが,UTF8では別の指定
の仕方が必要なようです。UTF8のコード体系について勉強します。その上で,改めておたずね
することも出てくるかと思います。その節もどうかよろしくお願いします。
ありがとうございました。