[Perl]UTF-8でエンコードされた文字列の文字数を取得するコード

Perlのlength関数ではバイト単位となるので、UTF-8でエンコードされている場合、漢字、ひらがな、カタカナなどは1文字で3となってしまいます。

ブログなどのアプリケーションのテキスト処理ではそれでは不都合な場合もことも多いので、半角英数も全角文字(漢字、ひらがな、カタカナなど) も1文字としてカウントする関数を作成することにします。

UTF-8では、

1バイト目の先頭ビットが0の場合は1バイト文字
1バイト目の先頭から3ビットが110の場合は2バイト文字
1バイト目の先頭から4ビットが1110の場合は3バイト文字
1バイト目の先頭から5ビットが11110の場合は4バイト文字
1バイト目の先頭から6ビットが111110の場合は5バイト文字
1バイト目の先頭から7ビットが1111110の場合は2バイト文字

という仕様ですので、1バイト目のビットの状態を調べることによって、その文字が何バイトかを調べることができます。

以下のコードでは、この仕様にもとづいて全角文字を含む文字列の文字数を取得しています。

#!/usr/bin/perl

use strict;
use warnings;

my $testAscii = "ABCDEFG";
my $testHira  = "あいうえお";
my $testKata  = "アイウエ";
my $testKanji = "愛々木";
my $testAll = "ABCDEFGあいうえおアイウエオ愛夢佐々木";

print "length($testAscii) = ".length($testAscii), "\n";
print "strlen_utf8($testAscii) = ".strlen_utf8($testAscii), "\n";

print "length($testHira) = ".length($testHira), "\n";
print "strlen_utf8($testHira) = ".strlen_utf8($testHira), "\n";

print "length($testKata) = ".length($testKata), "\n";
print "strlen_utf8($testKata) = ".strlen_utf8($testKata), "\n";

print "length($testKanji) = ".length($testKanji), "\n";
print "strlen_utf8($testKanji) = ".strlen_utf8($testKanji), "\n";

print "length($testAll) = ".length($testAll), "\n";
print "strlen_utf8($testAll) = ".strlen_utf8($testAll), "\n";

exit;

# UTF-8でエンコードされた文字列の文字数を取得する。
sub strlen_utf8 {
    my ($text) = @_;

    my $textlen = length($text);
    my $pos = 0;
    my $count = 0;

    while ($pos < $textlen) {
        my $code = ord substr($text, $pos, 1); # 先頭のASCIIコード値を取得
        my $bytelen = _bytesize($code);
        $pos += $bytelen;
        $count++; # 文字数をカウント
    }

    return $count;
}

# 文字のバイト長を求める
sub _bytesize {
    my ($code) = @_;
    my $size = 1;
    if (0x80 & $code) { # 1バイト文字以外
        $size++;
        $code <<= 1;
        for my $i (2 .. 8) {
            last if (!(0x80 & $code));
            $size++;
            $code <<= 1;
        }
    }
    return $size;
}

strlen_utf8関数では、substr関数を使用して1バイト目のASCIIコード値を取得し、 _bytesize関数を呼び出して文字のバイト数を求め、1文字分の処理を行うたびに文字数をカウントアップしています。

_bytesize関数ではパラメータで渡されたコード値の場合の文字のバイト数を、コード値のビットの状態から判定し 戻り値として返しています。

ゼロからわかる Perl言語超入門
技術評論社 著者:高橋 順子


amazon.co.jpのカスタマーレビューを見る
powered by amalink

[2243] Posted by kagahiro at 2012/12/12 11:56:21
オープン | 1 point | Link (3) | Trackback (0) | Comment (1)

キーワード
Perl 文字数 サンプル プログラム コード 

kagahiroのホームページ


[Perl]UTF-8でエンコードされた文字列の文字数を取得するコード 関連リンク

[Perl]1バイト(8bit)の10進数を2進数の文字列に変換するコード
Perlの関数を使用して、以下の手順で10進数を2進文字列に変換することができます。sprintf関数で10進数を16進文字列に変換pack関数で16進文字列をバイナリーにパックunpack関数で2進文字列に変換例えば、文字列の先頭...
[Perl]UTF-8でエンコードされた文字列の部分文字列を取り出すコード
Perlのsubstr関数ではバイト単位の操作になるので、漢字、ひらがな、カタカナなどの全角文字を文字数で指定して部分文字列を取り出すことができません。それでは不都合なことも多いので、半角英数も全角文字も1文字と...
[C言語]UTF-8でエンコードされた文字列の文字数を取得するコード
C言語のstrlen関数では文字列の長さとして返ってくる値はバイト単位となるので、UTF-8でエンコードされている場合、漢字、ひらがな、カタカナなどは1文字で3となってしまいます。Webアプリケーションのテキスト処理で...

[Perl]UTF-8でエンコードされた文字列の文字数を取得するコード トラックバック

トラックバックURL :


[Perl]UTF-8でエンコードされた文字列の文字数を取得するコードへのコメント

1 Posted by kagahiro at 2012/12/12 15:26:49
よく見ると、_bytesize関数がちょっと冗長ですね。

詳細の入力フィールドを表示する

おすすめ  (チェックしてコメントすると最新情報に掲載)
コメント :

< 前の投稿      次の投稿 >

アクセスランキング

今日のアクセスランキング TOP 10

  1. SQLのSELECT文で先頭から上位(TOP)10件のレコードを取得する方法(SQL Server、Oracle、MySQL、PostgreSQL) (77 PV)
  2. Google News (グーグルニュース)日本版 (13 PV)
  3. Dailymotion(デイリーモーション) - 動画共有サイト (9 PV)
  4. [将棋]将棋実況ユーチューバーのクロノさんが朝日新聞のクレームで棋譜中継を配信中止 (8 PV)
  5. [食べ物]七草粥(ななくさがゆ) (6 PV)
  6. CommentPP 1.3のリリース (5 PV)
  7. 「CASH(キャッシュ)」アイテム(ブランド品やガジェット)の写真を撮れば審査なしで現金化できるサービス (4 PV)
  8. [将棋]中学生プロ棋士「藤井聡太四段」が上州YAMADAチャレンジ杯で3連勝し連勝記録を23連勝に伸ばす (4 PV)
  9. ウェブページを1回だけリロード(再表示)する方法 (3 PV)
  10. Google(グーグル) 日本版 (3 PV)

今月のアクセスランキング TOP 10

  1. グーグルニュース日本語版が見れない (3271 PV)
  2. SQLのSELECT文で先頭から上位(TOP)10件のレコードを取得する方法(SQL Server、Oracle、MySQL、PostgreSQL) (3227 PV)
  3. Google News (グーグルニュース)日本版 (1100 PV)
  4. [将棋]将棋実況ユーチューバーのクロノさんが朝日新聞のクレームで棋譜中継を配信中止 (292 PV)
  5. 「CASH(キャッシュ)」アイテム(ブランド品やガジェット)の写真を撮れば審査なしで現金化できるサービス (192 PV)
  6. Google(グーグル) 日本版 (170 PV)
  7. ウェブページを1回だけリロード(再表示)する方法 (166 PV)
  8. [C言語]UTF-8でエンコードされた文字列の部分文字列を取り出すコード (136 PV)
  9. 将棋ウォーズスーパープレミアムプラン販売開始、香川愛生女流三段のボイスが選択可能 #将棋 (119 PV)
  10. アマゾンで買った商品(荷物)が届かない #デリバリープロバイダ (107 PV)

アクセス統計

ディレクトリ

関連サイト