myfinderの技術や周辺的活動のblog

2009年6月27日土曜日

Unicode::EastAsianWidthを使う

文字列を特定サイズの画像に埋め込むプログラムを書く機会があり、文字幅を計算する必要に迫られた。
すなわち「全角」を2文字「半角」を1文字分として数えたい、というケース。
(画像に埋め込むフォントは等幅を想定してます)

文字幅を計算する必要がある、ということはlengthなんかの文字数でのカウントはできない。

そこでいろいろ考えたりググったりしてみたところ、tokuhiromさんのblogでUnicode::EastAsianWidthの話を見つけた。

このモジュールはUnicodeコンソーシアムの定めるEastAsianWidthに基づき「全角に該当する文字」「半角に該当する文字」etcにあたるUnicode属性を提供するもので、useすると下記のようなUnicode属性が正規表現で使えるようになる。

/(?:(\p{InFullwidth}+)|(\p{InHalfwidth}+))/g

これを使うと「文字幅」をカウントできるようになるのです。
下記はそのプログラムの一例

use strict;
use warnings;

use Unicode::EastAsianWidth;
use utf8;

sub visualLength {
my $text = shift or '';

my $length = 0;

while ($text =~ /(?:(\p{InFullwidth}+)|(\p{InHalfwidth}+))/g) {
# 全角に該当すれば2、そうでなければ1インクリメント
$length += ($1 ? length($1) * 2 : length($2));
}

return $length;
}

my $text1 = "あいうえお"; # 10
my $text2 = "hogehoge"; # 8

print visualLength($text1), "\n";
print visualLength($text2), "\n";

多少冗長なコードかも。

ちなみにその「EastAsianWidth」の定義ってどんなん?という疑問がわいた方はここを見ると全部のってます。

補足
Unicode関係で超参考になったページ
http://totonica.s41.xrea.com/doc/delphi_tiburon/doc_unicode/eastasianwidth.htm

1 件のコメント:

myfinder さんのコメント...

近くの方から突っ込みをいただいたので、use warnings;と、visualLengthの引数を受け取るところに「or ''」を追加しました。