それ、メッセージ花火でわざわざ伝えること?

jcode.plを使って、
入力された文字列を例えば30文字ぐらいに切ってファイルに書き込む処理をしていますが、
文字列によっては最後の文字が文字化けしてしまうものがあります。
この場合どうすれば良いのでしょうか?

例)
「はじめまして」

「はじめま」にしてファイルに書き込むと
「ま」の文字が文字化けする。

現在の切り取り処理方法
$in = substr($in,0,30);

質問者からの補足コメント

  • 回答ありがとうございます。
    >フォーム側でUTF-8にして処理したら??
    これはどういう意味でしょうか?
    cgiファイルも出力するファイルもUTF-8にはしてあります。

    No.1の回答に寄せられた補足コメントです。 補足日時:2016/03/27 19:03
  • 回答ありがとうございます。

    Perl5.8.8です。
    jcode.pl,v 2.13 2000/09/29
    中を見ると「UTF-8」の記述がありませんので対応していないようです。

    この状態でjcodeでsjisに変換しています。
    jcode'convert(*xxx,'sjis');
    CGIも出力するファイルもブラウザ上も「UTF-8」にしている状態です。
    これが原因で文字化けするのでしょうか?
    でも文字化けするのは一部の文字だけです。

    また、下記の記述をすると「Internal Server Error」が出てしまいます。
    use utf8;
    binmode STDIN, ":utf8";
    binmode STDOUT, ":utf8";

    No.2の回答に寄せられた補足コメントです。 補足日時:2016/03/27 23:15
  • 下記を $in = substr($in,0,30); すると最後に「?」のような記号が不可される
    タイトル(15文字以内)

    バイナリでみると最後は下記のようになっています。
    85 29 E3 80

    「Internal Server Error」エラー内容
    utf8.pm: Can't locate utf8.pm in @INC (@INC contains: /usr/lib/perl5/5.00503/i386-linux /usr/lib/perl5/5.00503 /usr/lib/perl5/site_perl/5.005/i386-linux /usr/lib/perl5/site_perl/5.005 .) at updent.cgi line 54. BEGIN failed--compilation aborted at updent.cgi line 54.

    No.3の回答に寄せられた補足コメントです。 補足日時:2016/03/28 01:37
  • 結果的にどのような対処をしたら用でしょうか?
    サーバ側ではPerlバージョンは5.8.8と謳っています。
    しかし中身は違うと言う事でよいでしょうか?

    >CGIの先頭の #! を変えることで
    こちらは具体的にどのようにするのでしょうか?
    #!/usr/bin/perl
    この部分のことでしょうか?

    No.4の回答に寄せられた補足コメントです。 補足日時:2016/03/28 09:35

A 回答 (7件)

> 結果的にどのような対処をしたら用でしょうか?



わかっている限りの現状での暫定的な対策は
「UTF-8の多バイト文字を途中で切ったりしないsubstr相当の関数を用意して、標準のsubstrの代りに使う」
です。
どこかで探すか、自作してください。


根本的には、設計のやりなおしからでしょう。
 UTF-8を期待しているのに、UTF-8に対応していないjcode.plを使って、何故かsjisに変換しようとして、たまたまUTF-8になって...
これでは、何が「正しい」修正なのか、なんか考えられません。

文字コードの変化も含めて、流れを決めましょう。


> こちらは具体的にどのようにするのでしょうか?
> #!/usr/bin/perl
> この部分のことでしょうか?

そうですが、あくまで、「可能性です」
複数のバージョンのPerlをインストールして、実行時に選ぶ、ということは、よくあることです。
その際によく使われるのは、次のような方法です。
 (1)/usr/bin/perl はリンクで、リンク先を切り変えることで、バージョンを変える
 (2)/usr/bin/perl は「ランチャー」で、設定によって、実際に実行するPerlを切り替える
 (3)各バージョンで名前を変える perl58 perl5.8 等
 (4)インストールするディレクトリを変える。 /usr/local/perl58/bin とか /opt/local/bin とか
 (5) (3),(4)の複合
では、実際にどれが使われているのか、と言われても、そのサーバーの管理者に聞かなければわかりません。
加えて
 (6) Perl5.8はインストールされていない(5.8は別のサーバー、上級,有料会員等に登録する必要あり 等)
という可能性もあります。

既出のように「サーバーの管理者やサポートに聞いてください」としか答えようがありません。
    • good
    • 0

「サーバ側」に


use utf8;
とすると #3 への補足にあるようなエラーが出ることから Perl のバージョンは 5.005_03 であるように見えるので, どうすれば Perl5.8.8 を使えるようになるのか教えてほしい
と質問するしかないんじゃないかな. あ, もちろん質問するときにはちゃんとそのエラー内容もコピペでつけておくこと.

少なくとも, この状況は外部の人間にはどうしようもない.
    • good
    • 0

>>フォーム側でUTF-8にして処理したら??


>これはどういう意味でしょうか?
補足から、HTMLのフォームからサーバーに送信されてきたデータをCGIで処理して書き出す作業だと思われます。
 ブラウザは、フォームのデーターを指定がない場合は、そのHTMLの文字コードで送信してくるはずです。
 <form action="***" method="post" accept-charset="euc-jp">
ならeucでね。

そうすれば、とりあえずは
Perlメモ#特定の長さで折り返す( http://www.din.or.jp/~ohzaki/perl.htm#JP_Fold )
の方法で可能になる。

 詳しい説明はサイトをご覧になってください。古い資料です。


今はPerlはUTF-8を扱えますから、楽です
<form action="***" method="post" accept-charset="utf-8">
が、
 送信されてくるデーターの改行コードは異なるかもしれませんので、いったん改行コードを統一したのちに、
use Encode qw(decode);
・・・・・・・・
my $text = $FORM{'text'};

my $cnverted_text = decode('utf-8', $c_text);
としてからカウントします。
 日本語は3バイト
    • good
    • 0

jcode.plを確認したところ、 sjis→sjis変換は、[無変換」となります。

(オプション無しの場合)
おそらく
jcode'convert(*xxx,'sjis');

・$xxx に UTF-8で書かれたバイト列が入っている
・convertで、$xxxの文字コードを判定する
 → UTF-8は対応していない
 → Shift_JIS だと判定される
・convetで sjisに変換
 → sjis→sjisなので、無変換
と動作していて、結果的に $xxx が UTF-8 として正しいバイト列になっている、ということのようです。


>85 29 E3 80

「タイトル(15文字以内)」
だと、UTF-8で「28バイト」。最後の「内)」が「E5 86 85 29」です。
30バイト以下なので、substr($in,0,30) は $in と同じことです。

「85 29」は「内)」の末尾2バイトでしょう。残りの「E3 80」は、追加されてしまった何かです。


で、
「タイトル(15文字以内) 」 (末尾に全角空白)
を確認したところ、UTF-8で「31バイト」。最後の「内) 」が「E5 86 85 29 E3 80 80」です。
substr($in,0,30) で30バイトにするので、最後の1バイトが捨てられます。
末尾1バイト削除すると、「E5 86 85 29 E3 80」になります。
文字化けしているものと一致します。

やはり、「本来1文字のはずのバイト列の途中で切りとってしまっている」のが原因です。



> utf8.pm: Can't locate utf8.pm in @INC (@INC contains: /usr/lib/perl5/5.00503/i386-linux

@INCに入っているディレクトリに 「5.00503」 とあります。
これは「5.005.03用」という意味ですから、使われているPerlも、5.8.8ではなく、5.005.03 だと思われます。

5.005.3だと、encode/decodeによる方法は使えません。
CGIの先頭の #! を変えることで、5.8を使うように設定できるかもしれません。
この回答への補足あり
    • good
    • 0

「本来1文字のはずのバイト列の途中で切りとってしまっている」の可能性が高いですから、


まずは「日本語に対応したsubstrを作る」を試してください。

また、出力されたファイルをバイナリエディタやダンプで調べて、文字化けしている箇所がどんなバイト列になっているか調べましょう。
例えば Linux でodコマンドが使えるなら
od -t x1c 出力されたファイル
というようにすると、16進数と文字とでファイルの中を確認できます。



> また、下記の記述をすると「Internal Server Error」が出てしまいます。
> use utf8;
> binmode STDIN, ":utf8";
> binmode STDOUT, ":utf8";

ブラウザでは Internal Server Errorとしか出てこないので、具体的に何が問題になっているかがわかりません。
サーバーのログを見るとか、 use CGI::Carp qw(fatalsToBrowser); を使ってエラー内容を確認してください。
http://perldoc.jp/docs/modules/CGI-2.89/CGI/Carp …

5.8.8 なら、utf8フラグ付き文字列が使えるはずです。
この回答への補足あり
    • good
    • 0

まず2点確認です。



Perlのバージョンは?

そのjcode.plのバージョンは?本家ですか派生版ですか?
本家だと UTF-8に対応していません。
UTF-8に変換されているのではなく、元々UTF-8だったものが「無変換」で処理されているだけかもしれません。


jcode.plが準標準だった時代の話。
あなたには「はじめまして」という6文字に見えるかもしれませんが、Perl内部では「AbcDefGhiJklMnoPqr」といったような18文字バイト列に見えています。
# UTF-8の場合、平仮名1文字は、3バイトの文字列で対応しています。Shift_JISやEUC-JPなら2バイトです。
# 実際には、 A=「は」の1バイト目、b=「は」の2バイト目 c=「は」の3バイト目 となっています。

substr関数が対象にするのは、「Perl内部」です。
AbcDefGhiJklMnoPqr から切り出して AbcDefGhiJ となっても、まったく気にしません。
ですが、これをUTF-8として表示させようとすると 「ま」の2バイト目以降が無いため、文字化けとなります。
# 文字化けで済んでいるのは、変換エラー時の対策がされているからです。
# エラー処理が不十分なプログラムだと、文字化け程度では終わらず、システムエラーになって止まったり、暴走してハードディスクを破壊したり、といったことも発生し得ます

対策は、「単純に文字数(=バイト数)で分割しない」ことです。
「日本語1文字」が2つに分割されているようなら、分割位置を前後にずらします。
そんな対策をした、「漢字対応substr」を自作するか、どこかで探す必要があります。

UTF-8の場合、ビットパターンによって「1バイト目」と「2バイト目以降」との区別が付くので、「後半の文字列の先頭が『2バイト目以降』なら、その文字を前半へ移動する / あるいは、前半の最後の文字を後半へ移動する」といった処理ができます。
Shift_JISやEUC-JPだと、「元の文字列の先頭『1文字』を取り出して、前半に追加」を『文字数』繰り返す、といったことが必要です。



最近のPerlでは、日本語を日本語文字のまま扱える仕組みがあります。
「utf8フラグ付き文字列」とか呼ばれる、内部形式です。
Encodeモジュールを使うなどして
 (外部の) UTF-8やShift_JIS,EUC-JP等のバイト列 → decode → 内部形式(utf8文字列)
と内部形式に変換します。
こうすると、 substr等の関数、 各種正規表現等が、日本語の1文字を「1文字」として扱うようになります。
 $s = 'はじめまして' ;
 $s =~ /^(.)/;
 # バイト列の場合 $1は「『は』の1バイト目」
 # utf8付きの場合、$1は「は」

ファイルや画面に出力するときは、外部用のバイト列にencodeします。
 内部形式(utf8文字列)→encode→(外部用の) UTF-8やShift_JIS,EUC-JP等のバイト列

問題は、旧来の方式との違いが多いことです。
短かいプログラムなら、あるいは、これから新しく作るプログラムならいいのですが、既に動いている大きなプログラムを旧来方式から現在流に変更しようとすると、手間になります。

また「最近のPerl」とあるように、バージョンによってはこちらの方法が使えなかったり不安定だったりします。
この回答への補足あり
    • good
    • 0

文字コードをShift_JISで扱う限りその問題は出てきます。


Jcode.plを使わなくても最近のPerlでしたら、UTF-8で扱えるので、フォーム側でUTF-8にして処理したら??
 それともHTTPを経由せず直接Perlで処理しているのですか??
この回答への補足あり
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!