EUC-JP文字列をバイト数でカットした時の末尾の処理

当サイトの徒委記RSSBloglinesでチェックしているのですが、Bloglinesでは以前に登録されたitemについては、その後itemが更新されてもdescription要素の内容が変化しない限りは更新したとみなさないようです。RSS 1.0についてはdc:dateの値も見てもらいたい気もするのですが、一方で、YukiWikiは常にヘッドライン(記事の1行目)をitemのdescription要素としたRSSを出力するので、RSSからではページ内のどの部分が更新されたのか分からないという欠点があることに気付きました。

そこで、以下のようにして取り出した文字列をitemのdescription要素とすることを思いつきました。

  1. Wikiページの差分情報より、追加された行を抜粋。
  2. HTMLに変換
  3. HTMLタグを除去

2番目と3番目の処理は、Wiki独自の記法を除去するためです。差分内容は更新ごとに変化するだろうから、これをdescription要素とすればBloglinesでも更新したものと見なしてくれるだろう、という目論見です。

で、その改造はなんとか出来たのですが、試しにそのようにしたRSSを見てみると、追加部分が多い場合はdescription要素の内容もそれだけ多くなることに気付きまして、概要として適当な分量でdescription要素の内容をカットすることを考えました。

さて徒委記ではEUC-JPの文字コードを使用しているのですが、EUC-JP文字列を或るバイト数でカットすると、マルチバイトの断片が末尾に残ってしまう場合があり、文字化け等の元になりそうです。幸いにして以前にUTF-8で似たようなことを考えたことがあったので、EUC-JPのバイト値の範囲が分かれば、同じように正規表現で対処できると考えました。

というわけで、文字コードの話に載っていたEUC-JPのバイト値の範囲を参考に、以下のようなスクリプトを書きました。

use strict;

my $euc = '「EUC-JP文字列末尾の余りバイトをカット」';

for (my $i = length($euc); $i >= 0; $i--) {
    my $cut = substr($euc, 0, $i);
    $cut = round_eucjp($cut);
    printf("%2d: %s\n", length($cut), $cut);
}

sub round_eucjp {
    my $str = shift;
    $str =~ s/
        ((?:^|[\x20-\x7E]|\x8E[\xA1-\xDF]|\x8F)
        (?:[\xA1-\xFE]{2})*)[\xA1-\xFE]$
    /$1/x
    or $str =~ s/[\x8E\x8F]$//
    or $str =~ s/\x8F[\xA1-\xFE]$//;
    return $str;
}

以上の仕組みを徒委記スクリプトに組み込み、今のところRSSも思っていた通りに出力されているようですが、実のところ夜中のやや眠い時にざっと考えて書いたものでありますので、改善点等ありましたらご指摘頂けると有難いです。