日本語対応トリミングフィルタ(バグ修正)
文字化けの原因は、指定したバイト数よりも元の文字列長が短くてトリミングされない場合に文字コードがeucに変換されたままリターンしているのが原因でした。すみません。
なんでこんなバグに気付かなかったんだろう・・・。
文字化けのバグを修正したソースを掲載しておきます(元のエントリーのソースも修正しました)
2004/3/1追記:このソースにもまだバグがあります。最新版はこの記事を参照してください。
2004/3/29追記:このスクリプトはmuraさんの記事(M’s folder: MT 長いタイトルをトリミングする)で公開されているものをEUC以外の文字コードに対応するように改変したものです。
# 指定された文字数(半角文字数)にトリミングするフィルタ
package MT::Plugin::Trimj;
use MT::Template::Context;
use MT::ConfigMgr;
MT::Template::Context->add_global_filter(trimj_to => sub {
my($str, $nstr, $ctx) = @_;
my $sippo = '...';
my $lenstr = length($str);
if($lenstr < = $nstr) {
return $str;
}
my $c = MT::ConfigMgr->instance->PublishCharset;
my $conv_in;
if (lc $c eq lc 'Shift_JIS') {
$conv_in = 'sjis';
} elsif (lc $c eq lc 'ISO-2022-JP') {
$conv_in = 'jis';
} elsif (lc $c eq lc 'UTF-8') {
$conv_in = 'utf8';
} elsif (lc $c eq lc 'EUC-JP') {
$conv_in = 'euc';
}
my $jcnv;
eval 'use Jcode;';
if($@){
require 'jcode.pl';
$jcnv = 'jcode::convert';
}else{
$jcnv = 'Jcode::convert';
}
if ($conv_in ne 'euc') {
&$jcnv(\$str, 'euc', $conv_in);
}
my $out = substr($str,0,$nstr);
if ($out =~ /\x8F$/ or $out =~ tr/\x8E\xA1-\xFE// % 2) {
chop $out;
if($out =~ /\x8F$/){
chop $out;
}
}
$out .= $sippo;
# 尻尾を付けたくない場合は、コメントアウトのこと。
if ($conv_in ne 'euc') {
&$jcnv(\$out, $conv_in, 'euc');
}
return $out;
});
1;
2 月 6th, 2004 at 19:45:30
今日も弄る(^_^;)
Bookmarkletって機能が便利って事で使ってみたら何と文字化けして読めん(笑)。早速検索した。 Milano::Monolog: Bookmarklet文字化け対策TrackBackの文字化けを解消していい気になっていたら、どこか…
3 月 1st, 2004 at 17:29:35
はじめまして。
こちらのTrimjプラグイン、非常に参考になりました。
なお、一部改良できる個所がありましたのでコメントさせていただきます。
utfは全角文字が2バイトではないため、eucに変換する以前にlengthを比較してしまうと希望どおりの文字数が得られません。
そのため、eucに変換してから文字数を比較すると希望どおりの結果が得られると思います。
以下はソース–
# 指定された文字数(半角文字数)にトリミングするフィルタ
package MT::Plugin::Trimj;
use MT::Template::Context;
use MT::ConfigMgr;
MT::Template::Context->add_global_filter(trimj_to => sub {
my($str, $nstr, $ctx) = @_;
my $sippo = ‘…’;
#文字数がオーバーしていなければtmpを返す
my $tmpstr = $str;
my $c = MT::ConfigMgr->instance->PublishCharset;
my $conv_in;
if (lc $c eq lc ‘Shift_JIS’) {
$conv_in = ’sjis’;
} elsif (lc $c eq lc ‘ISO-2022-JP’) {
$conv_in = ‘jis’;
} elsif (lc $c eq lc ‘UTF-8′) {
$conv_in = ‘utf8′;
} elsif (lc $c eq lc ‘EUC-JP’) {
$conv_in = ‘euc’;
}
my $jcnv;
eval ‘use Jcode;’;
if($@){
require ‘jcode.pl’;
$jcnv = ‘jcode::convert’;
}else{
$jcnv = ‘Jcode::convert’;
}
if ($conv_in ne ‘euc’) {
&$jcnv(\$str, ‘euc’, $conv_in);
}
#比較をここに移動
my $lenstr = length($str);
if($lenstr <= $nstr) {
return $tmpstr;
}
my $out = substr($str,0,$nstr);
if ($out =~ /\x8F$/ or $out =~ tr/\x8E\xA1-\xFE// % 2) {
chop $out;
if($out =~ /\x8F$/){
chop $out;
}
}
$out .= $sippo; # 尻尾を付けたくない場合は、コメントアウトのこと。
if ($conv_in ne ‘euc’) {
&$jcnv(\$out, $conv_in, ‘euc’);
}
return $out;
});
1;
– 以上、大変でしゃばった真似をして申し訳ありませんでした。
今後ともよろしくお願いいたします。
3 月 1st, 2004 at 17:31:07
先ほどのコメント、ソースの丸投げであるため非常に長々としてしまいました。
ご都合で編集していただければありがたいです。
3 月 1st, 2004 at 18:13:48
日本語対応トリミングフィルタ(再度バグ修正)
kubotさんより、utf-8からeuc変換前に文字数を判断してしまうと、3バイトコードがあるときに希望する文字数を得られないのではないか、というご指摘を受けました。確かにそのとおりです…
3 月 1st, 2004 at 18:26:09
kubotさん、はじめまして。
わざわざご指摘いただき、どうもありがとうございました。m(_,_)m