fold
お久しぶりです。
まだ、試行錯誤の後にこんな例題を書き残す程度の能力です。
とある古いPerlのコードの書き直しで、文字列を1文字ずつ、配列に代入して返すという課題がありました。
前は、
#!perl use strict; use warnings; use utf8; use Encode; use Jcode; binmode STDOUT, ":utf8"; binmode STDIN, ":utf8"; sub str_jfold($$); sub fold_print($); sub main(); sub str_jfold($$){ # FAILs when processing unicode my $str = shift; #指定文字列 my $byte = shift; #指定バイト my $j = Jcode->new($str); my @result = (); foreach my $buff ( $j->jfold($byte) ){ push(@result, $buff); } return(@result); } sub fold_print($) { my $text = shift; my @result = str_jfold($text, 1); foreach my $f (@result){ next if $f eq ''; print "fold: $f\n"; } } sub main(){ my $input = <>; my $inputu = decode_utf8($input); fold_print($inputu); } main();
のような感じだったんですが、出力が
$ perl utf8_fold.pl Hatena::Diary is like but a bit different from weblog. fold: H fold: a fold: t fold: e fold: n fold: a fold: : fold: : fold: D fold: i fold: a fold: r fold: y (...) $ perl utf8_fold.pl はてなダイアリーはブログみたいなサービス。 Use of uninitialized value $f in string eq at utf8_fold.pl line 49, <> line 1. fold: ã?¯ fold: ã?訢 fold: ã?ª fold: ã?? fold: ã?¤ (...)
と、日本語の入力に対してうまくいきませんでした。
修正したものが、
sub str_nfold($$); sub str_nfold($$){ #これならunicodeでもOK my $str = shift; my $mojisu = shift; my @temp0 = split(//, $str); my @temp1; my @temp2; for (my $i = 0; $i < $#temp0 + 1; $i += $mojisu) { @temp2 = (); for (my $j=0; $j<$mojisu; $j++){ push @temp2, $temp0[$i+$j]; } push @temp1, join('', @temp2); } return @temp1; } sub fold_print($) { my $text = shift; #my @result = str_jfold($text, 1); my @result = str_nfold($text, 1); foreach my $f (@result){ next if $f eq ''; print "fold: $f\n"; } } # (以下略)
ということで、表示は
$ perl utf8_fold.pl はてなダイアリーはブログみたいなサービス。 fold: は fold: て fold: な fold: ダ fold: イ fold: ア fold: リ fold: ー (...)
となってくれました。
str_jfoldが不成功だった理由
Perlは、5.8.0以降、内部表現の文字コードとして標準でunicodeをサポートする、というか優先して使用するようになったそうです。
その前は、バイト列をバイト列として扱うことができた。古いコードはその時代に書かれたものでした。標準入(出)力のbinmodeをUTF-8に設定すると、内部表現において2バイト〜6バイトのunicodeをASCII文字で表現したものに変換されるので、EUC-JPやShift_JISでの成功率が高かった特定バイト単位での分割には成功しない、と。
なお、文字数については次ぎの説明がみつかりました。
文字数とデータサイズが比例しないため、文字数を調べるには先頭から全データを読み取る必要がある。ただし、Unicodeでは一部の文字を合成によって表現することもできるから(例:「ぱ」は、U+3071のほかにもU+306F U+309Aでも表現できる)、Unicodeを採用する場合、文字列の文字数をその文字列のバイト数から計算できないことは、UTF-8に限ったことではない。