• 締切済み

PERLのSHIFT_JISの振る舞いについて

PERLでプログラムを作る時、SHIFT-JIS形式で長音符(ー)があると、エスケイプしてもエラーが出てしまい困っています。 また、ホームページそのものがSHIFT_JIS形式のため、UTF-8など他の形式を使うと煩雑になるため避けたいと思っています。 エスケイプさせるなど簡単な方法は無いものでしょうか? また、こちらはご存じでしたら教えていただきたいのですが、「¥」マークでエスケイプしてもうまくいかない文字には他にどの様なものがありますでしょうか? ---test.pl---SHIFT_JIS形式---- $| = 1; $test = "\テ\ス\タ\ー"; $test =~ s/\テ\ス\タ\ー/tester/; print $test; エラーを見ると、 Unmatched [ in regex; marked by <-- HERE in m/\テ\ス\タ\ー <-- HERE / at test.pl line 3. とでます。

  • Perl
  • 回答数4
  • ありがとう数2

みんなの回答

  • kumoz
  • ベストアンサー率64% (120/185)
回答No.4

変数の代入文に直接日本語文字列を書かずに、外から読み込むようにすればかなりのエラーは防げると思います。 $pattern = <DATA>; chomp $pattern; $string = <DATA>; $string =~ s/\Q$pattern/tester/g; print $string; __DATA__ テスター テスターを変換して表示します

  • kmee
  • ベストアンサー率55% (1857/3366)
回答No.3

いわゆる「Shift_JISのダメ文字」というのは、「全角文字」を「1文字」ではなかく「2バイト」と判定してしまう処理系で、その2バイト目が特殊な意味を持つ記号と一致してしまうめに発生するものです。 テスター というShift_JISの文字列は AeBXC^D[ という文字列とほぼ同じ扱いになります。A,B,C,Dは1バイト目で実際は128以上の文字コードを持つものです。 通常、特殊な文字の前に\を付けて、特殊な意味を取り消す、と本には出ています。 それで\テ\ス\タ\ー としたのでしょうが、上の例に従えば \Ae\BX\C^\D[ とA,B.C.Dをエスケープしているだけで、2バイト目の^,[はまったくエスケープされていません。 よくある ソ\ は最後が\だから有効な技です。 正直、簡単じゃないです。 ・ーのあと[を無効にするために[] を付けてー[]とする ・特殊文字を無効にする\Q~\Eで囲む などがありますが。 内部ではutf-8、出力をShift_JISというのが無難かもしれません

回答No.2

No1です。 例の場合テスターの「ー」の後の文字が「¥」ではなく「/」なのでエラーになってるのではないかなと。 つまり「ー」や「表」の2バイト文字はコードにすると「5C」が2バイト目になり、この5Cを1文字に直すと「¥」になります。 「ー」の場合だとプログラム内部では「815C」と認識され、5Cの部分が「¥」と解釈されてしまうため、結果として「(81の文字:?)+(5Cの文字:¥) = 文字化けした変な文字ということになるのです。 index()を用いてと書いたのは例えば「テスター」の場合4文字目に「ー」が来るので、特定の文字が見つかったら「¥」を付加するような文字列にすればいいのでは?と思ったわけですが、ちょっと面倒ですね。 使ったことはないので何とも言えないですが、encode関数で正規表現に渡す前に変換すればうまくいくかもしれません。 ---test.pl---SHIFT_JIS形式---- $| = 1; $test = "\テ\ス\タ\ー"; $test =~ s/\テ\ス\タ\ー/tester/; # 追加 # 文字列をUTF-8に変換 $str = encode('UTF-8', $test); # 追加 # 変更 #print $test; print $str; # 変更 文字化けを起こす文字コードについては以下を参照してください。 http://www.geocities.co.jp/SiliconValley-Sunnyvale/6128/perl/bake.html

回答No.1

Shift-JISを正規表現で使うのは文字コードの問題で結構面倒ですので、index等で特定文字の後ろに\を付けてから正規表現に渡すなどの工夫が必要です。 参考になると思うので一読してみてください。 http://homepage1.nifty.com/nomenclator/perl/shiftjis.htm

aki_toyama
質問者

お礼

回答いただきありがとうございます。 ちょっと、説明文が理解できない(perl初心者)なのですが、 >index等で特定文字の後ろに\を付けてから正規表現に渡すなどの工夫が必要です はどういう意味でしょうか? 例では、念のため全てに¥マークを付けています。 これでは不十分と言うことでしょうか? 可能であればもう少し、分かり易く説明いただければ幸いです。 また、これは、今まで使ったことがなく、振る舞いがよく分かりませんので使うのは怖いのですが、紹介いただいたHPにVer5.8.Xより便利になったという記載がありましたので、ググってみたところ ---test.pl---SHIFT_JIS形式---- use encoding "shiftjis"; binmode STDERR, ":encoding(shiftjis)"; $| = 1; $test = "\テ\ス\タ\ー"; $test =~ s/\テ\ス\タ\ー/tester/; print $test; ---------------------------- を使うと上手に処理できるようでした。 参考 http://www.fl.reitaku-u.ac.jp/~schiba/perl/perlEncoding.html

関連するQ&A

  • 文字列比較

    文字列比較演算子で~の文字列の中に~が含まれていれば真を返すという下記のようなサンプルを作ったのですが、「ソ」「タ」「ゼ」「ー」の4文字だけ比較することができませんでした。エラーは 「ソ」 Unrecognized character \x94 at untitled2.pl line 5. 「タ」 エラーなし。ただし比較せず。 「ゼ」 Unmatched [ in regex; marked by <-- HERE in m/ゼ <-- HERE / at untitled2.pl line 4. 「ー」 Unmatched [ in regex; marked by <-- HERE in m/ー <-- HERE / at untitled2.pl line 4. と表示されましたのですが、これは上記の4文字に関しては部分比較することができないのでしょうか? それとも別の方法があるのでしょうか?どなたかご指導のよろしくお願いします。 環境はWindowsXP、ActivePerl、Httpdです。 ************************ $words1 = "アイウカキクスセソタチツゼー" ; $compare = "タ" ; if( $words1 =~ /$compare/ ){ print "比較対象文字が含まれています。\n" ; } else{ print "比較対象文字は存在しません。\n" ; }

    • ベストアンサー
    • Perl
  • SmartyでのShift-JIS使用

    現在、携帯サイトの構築を行っています。 EUC-JPならば問題なく表示されるのですが携帯電話はShift-JISをサポート。 一応、EUC-JPも表示はされますがサポート外である事実は変わりません。 そこで、表示に関してはShift-JISで行いと考えています。 (全ての携帯がEUC-JPでも問題なく表示できる確証がない限り表示はShift-JISを考えています。) しかし、今度はSmartyがShift-JISがサポート外。 普通にShift-JISを使うと文字化けを起こしたりエラーが表示されます。 PHPもShift-JIS、SmartyのテンプレートもShift-JISにすれば とりあえずはPHPからの表示する文字に関してはShift-JIS表示できますが Smartyテンプレートに直接書いた文字は文字化けを起こします。 自分なりに調べて http://blog.livedoor.jp/alpha1280/archives/50225918.html http://www.knym.net/wiki/index.php?PHP%2FSmarty のサイトを見つけて記事内に書いてあるPHPを利用してみました。 Smarty_Extends.phpをSmarty.class.phpと同じフォルダに作成して テンプレートをShift-JISで作成、プレフィルタとポストフィルタのコメントを外して Smarty_Extendsを利用して表示するPHPを作成↓ <?php include_once('Smarty_Extends.php'); $smarty = new Smarty_Extends('templates','templates_c'); $smarty->assign("test", "Shift-JISによる表示だよ。必須"); $smarty->display("Enc_Shift-JIS.tpl"); ?> エラーは出なかったんですが従来通り文字化け、何度もテストしているんですが判りません。 SmartyでShift-JIS表示の経験がある方、上記の問題点や解決作の判る方。 お力を頂ければ幸いです、宜しくお願い致しますm(_ _)m

    • ベストアンサー
    • PHP
  • アスタリスクを検索できません

    以下のテキストデータを、それぞれ*までの一行毎に配列に代入したいのですが、if文で*を検索しようとしてもうまくできません。 あいうえお* かきくけこ* さしすせそ* たちつてと* あいうえお* さしすせそ* あいうえお* 以上のものが元のテキストデータで、「あいうえお」を配列の0番目の要素、「かきくけこ」を1番目の要素、「さしすせそ」を2番目の要素・・・というようにしたいです。 現在のプログラムは、 hash.pl use encoding 'shift-jis'; $pattern = '*'; @txt1 = (); while(<>){ if($_=~/$pattern/){ $in=index($_,$pattern); $temp=substr($_,0,$in); push @txt1,"$temp"; } } print @txt1; となっているのですが、これをコマンドプロンプト上で動かすと、 Quantifier follows nothing in regex; marked by <-- HERE in m/* <-- HERE / at hash.pl line 5, <> line 1. というメッセージが表示されます。 *関連で問題があるのはわかるのですが、どうしても解決策が見つかりません。 よろしくお願いします。

    • ベストアンサー
    • Perl
  • perlをwindows環境でshift-jisのテキストファイルを読

    perlをwindows環境でshift-jisのテキストファイルを読み込み、読み込んだファイルをutf-8でファイルを書き込み(改行コードはLF)をする方法がわかりません。 サンプルプログラムを示してもらえると助かります。 書き込みを”binmode STDOUT, ":utf8";”にするだけでは、下記のようなエラーがでました。エラーの意味が良くわかりませんでした。わかれば教えてください。 Malformed UTF-8 character (unexpected continuation byte 0x82, with no preceding start byte) at utf.pl line 7.

    • ベストアンサー
    • Perl
  • chomp( shift(@array) )

    前々から疑問だったのですが、Perl 5.8 で @array = ("test\n", "hogehoge"); chomp( shift(@array) ); は Can't modify shift in chomp at XXXX.pl line X, near "))" というエラーの下実行できないのですが、なぜこの書き方が出来ないのでしょうか?

    • ベストアンサー
    • Perl
  • [perl5.8] SJISで出力したはずのファイルにutf8フラグが

    1)SJISで以下の2行を含むファイルを作成し、   sjis.txtという名前で保存します。 "ホツカイドウ" "北海道" 2)SJISで以下のスクリプトを作成します。 #=== one.pl === use encoding 'Shift_JIS'; use open IN => ":encoding(Shift_JIS)"; use open OUT => ":encoding(Shift_JIS)"; my $infile = 'sjis.txt'; my $outfile = 'sjis2.txt'; open(IN, "<$infile"); @lines = <IN>; close(IN); open(OU, ">$outfile"); print OU @lines; close(OU); 3)SJIJSで以下のスクリプトを作成します #=== two.pl === use encoding 'Shift_JIS'; use open IN => ":encoding(Shift_JIS)"; use open OUT => ":encoding(Shift_JIS)"; my $infile = 'sjis2.txt'; my $outfile = 'sjis3.txt'; open(IN, "<$infile"); @lines = <IN>; close(IN); open(OU, ">$outfile"); print @lines; close(OU); 4)one.pl を実行し、続いてtwo.plを実行すると 以下のエラーがコマンドプロンプトに表示されます。 #------------------------------------------- D:\zipcode\utf8mondai>two.pl Wide character in print at D:\zipcode\utf8mondai\two.pl line 14. "・趣セゑスカ・イ・・セ橸スウ" Wide character in print at D:\zipcode\utf8mondai\two.pl line 14. "蛹玲オキ驕・ これは何故なのでしょうか。 エラーメッセージは、printしようとしている 文字列にutf8フラグがついているという意味 らしいです。

    • ベストアンサー
    • Perl
  • shift-jisからutf8に変換

    解決に至らなかったので再度お尋ねします。 CGIのコードを見てくださいますか。 http://hotpegasus.bov.jp/mail.txt (必要な部分だけ表示しておりますので、そのままアップしても機能はしません) 改修した箇所は以下のです。 <meta http-equiv="Content-Type" content="text/html;charset=shift_jis"> &jcode'h2z_sjis(*contenido) &jcode'convert(*subject,'sjis'); &jcode'convert(*infor,'sjis'); &jcode'convert(*contenido,'jis'); &jcode'convert(*res_msg,'jis'); print "Content-type: text/html;charset=shift_jis\n\n"; ↓ sjis関連をutf8に書き換え、jcodeの頭文字をJに書き換え <meta http-equiv="Content-Type" content="text/html;charset=utf8"> &Jcode'h2z_utf8(*contenido) &Jcode'convert(*subject,'utf8'); &Jcode'convert(*infor,'utf8'); &Jcode'convert(*contenido,'utf8'); &Jcode'convert(*res_msg,'utf8'); print "Content-type: text/html;charset=shift_utf8\n\n"; require 'jcode.pl'をuse Jcode;に書き換え ※jcode::" となっている箇所はありません 結果 メールフォームはエラーや文字化けは出なくて成功しましたが、メール受信の際、ThunderbirdPortableメーラーでは全て文字化け(文字エンコーディングは「日本語ISO-2022jp」となっています)、ウェブメールのgmailでは内容は文字化けになっていませんが、タイトルが文字化けになっています。 どこが悪かったのでしょうか? 宜しくお願いします。

    • 締切済み
    • CGI
  • perl2exeでuse encodingが使えない

    下記のようなスクリプトを作成しました。 スクリプト名は test_kanji.pl ---------------- use encoding("shift-jis"); print "表現\n"; ----------------- 上記を実行すると、正しく”表現”の文字が表示されます。 これをperl2exeで実行形式に変換すると 下記のエラーが表示され、期待した結果が得られません。 Converting 'test_kanji.pl' to test_kanji.exe Warning: Can't locate I18N/Langinfo.pm at C:\Perl\lib\encoding.pm line 41 @INC = c:\perl\userlib, C:\Perl\lib, C:\Perl\site\lib, . 又、強引にtest_kanji.exeを実行すると encoding: Unknown encoding 'shift-jis' at C:\Perl\userlib\test_kanji.exe line 1 BEGIN failed--compilation aborted at C:\Perl\userlib\test_kanji.exe line 1. のようなメッセージが表示され、”表現”が表示されません。 perl2exeでuse encodingは使用できないのでしょうか。

  • Perl 強制終了の回避について

    Attempt to free unreferenced scalar とは? http://oshiete1.goo.ne.jp/qa4237453.html の続きです。 とりあえず、下に現状で分かる最小限の再現性があるスクリプトを 書いておきます。 print &opentmpl("body"); print &opentmpl('footer'); # これがない場合はエラーにならない sub opentmpl { my $fn = shift; my $VAR = shift || {}; my $file = &{$fn}(); &regex(\$file, $VAR, '__([A-Z_\d]+?(\[\d+?\])?)__', ['$VAR->{"%s"}', '$1']); &regex(\$file, $VAR, '&{(.+?)}&', ['%s', '$1']); return $file; return undef; } sub regex { my $str = shift; my $VAR = shift; my $pattern = shift; my $replace = shift; $$str =~ s/((([^\n]*?)$pattern(?=.*))+(\n?))/&func($1, $VAR, $pattern, @$replace)/egs; return; } sub func { my $str = shift; my $VAR = shift; my $pattern = shift; my $buf = shift; $str =~ s/$pattern/$@ = ''; $_ = eval(sprintf($buf, map { eval($_); } @_)); $@ ? $@ : $_/egs; if($str =~ /^\s*\n?$/s) { return; } return $str; } sub body { print "Content-type: text/plain; charset=shift_jis\n\n"; return <<'HTML'; &{ return &opentmpl('table', {'TEST' => 'test'}); }& HTML } sub table { return <<'HTML'; __TEST__ HTML } sub footer { return <<'HTML'; test HTML } 調べてみた限りではActivePerl for Win32以外のPerlでも同様のよう です。 (Linux上でも同様のようです) 5.8.8ではエラーになりますが、5.10.xではエラーにならないようです。 (同じ環境において5.8.8では再現し、5.10.0にバージョンアップすると 再現しなくなり、再度5.8.8にバージョンダウンすると再現します) 本番機の環境が5.8.8で勝手にバージョンアップなどができないため、 5.8.8で正常に動作するようにするにはどうしたらよいでしょうか。 結構、無駄も多いと思いますので全く同じ動作をしながらより効率の いい書き方ができたらいいなと思います。 (なお、実際には使用しているけど上記では使用していない部分が 含まれていてその部分がない場合もエラーにならないようです)

    • ベストアンサー
    • Perl
  • sedやperlでの2バイト文字を含む変換

    こんにちは。 sedコマンドは、texに付属していた日本語対応のものを使用しており、 perlはWindows用のActive Perl v.5.12.2を使用しています。 カレントディレクトリにあるファイルやフォルダにおいて、 名前を一括して変換したいと思い、以下のようなNameConv.batというバッチスクリプトを作成しました。 ____________________________________________________________ @echo off for /f "delims=" %%a in ('dir /b !opt!') do ( for /f "usebackq delims=" %%b in (`echo %%a^| sed -e "s/%~1/%~2/g"`) do ( move /y "%%a" "%%b" 1>nul 2>nul if not "%%a"=="%%b" echo 「%%a」→「%%b」 ) ) ____________________________________________________________ このバッチスクリプトを NameConv.bat " " "_" の様にして呼び出すと上手く行きました。 (この場合は、カレントディレクトリの全てのディレクトリとフォルダの名前において、 スペースがアンダーバーに変換されました。) ところが、 NameConv.bat "スペース" " " のように、第一引数に変換文字列に2バイト文字を使用すると、 以下のようなエラーメッセージが出て上手く行きませんでした。 sed: -e expression #1, char 14: Unterminated `s' command どうやら、 echo %%a| sed -e "s/スペース/ /g" といったコードは、上手く行かなかったようです。 そこで、この問題を解決しようと、以下のようなNameRep.plというPerlスクリプトを作成しました。 ____________________________________________________________ #日本語を扱うために必要な設定 use encoding "cp932"; use open ":encoding(cp932)"; use open ":std"; map{ binmode($_,":crlf"); } qw/STDIN STDOUT STDERR/; #置換操作 $name="$ARGV[0]"; $name =~ s/$ARGV[1]/$ARGV[2]/g; print "$name"; ____________________________________________________________ そしてこのスクリプトを for /f "delims=" %a in ('dir /b') do ( @perl NameRep.pl "%a" "スペース" "_" ) の様にしてコマンドラインから呼び出すことで、「スペース」という文字列が、 きちんと処理できるかを試したところ、以下のようなエラーメッセージが出ました。 Unmatched [ in regex; marked by <-- HERE in m/\x{00d8}\x{00f9}\x{005b} <-- HERE \x{00d8}/ at C:\Users\kei\NameRep.pl line 11. どうやら $name =~ s/$ARGV[1]/$ARGV[2]/g; の部分で、$nameや$ARGV[1]に2バイト文字が含まれていると、上手く行かないようです。 #日本語を扱うために必要な設定 以下のコードブロックで、シフトJISに対応できるはず(少なくとも今までは問題なく扱えました) なのですが、何故か上手く行きません。 そこで、sedコマンドやperl、特にperlにおいて、シフトJISコードでの2バイト文字の扱い方を御存じの方に、何かアドバイスを頂きたいと考えています。 長くなりましたが、どうぞよろしくお願い致します。

    • ベストアンサー
    • Perl