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に限ったことではない。

(http://ja.wikipedia.org/wiki/UTF-8)
ふむふむ。