EUC-JPでマルチバイトを含む文字数を正確にカウントする

EUC-JPのシングルバイト文字のうち、コントロールコードを除いたASCII文字は[\x20-\x7E]。これはそのまま数えれば問題ない。

my $n = ($str =~ tr/\x20-\x7f/\x20-\x7f/);

一方、EUC-JPの2バイト文字は [\x8E\xA1-\xFE][\xA1-\xFE](うち\x8E[\xA1-\xDF]は半角カナ)、3バイト文字は \x8F[\xA1-\xFE][\xA1-\xFE] 。すなわち、1文字につき2バイトが[\x8E\xA1-\xFE]にマッチする。よって、

my $n = ($str =~ tr/\xa1-\xfe/\xa1-\xfe/) / 2;

は半角カナを含むマルチバイトの文字数。以上を組み合わせて、

my $str = '日本語文字abcdeあいうえおアイウエオ';
my $n = ($str =~ tr/\x8e\xa1-\xfe/\x8e\xa1-\xfe/) / 2 + ($str =~ tr/\x20-\x7f/\x20-\x7f/);
print "$n\n";  # 結果は20