文字コードUTF-8の多言語を含むテキストデータの中に日本語を含むかどうかを調べる方法を探しております。

以下のいずれかの情報。知っている方おしえてください。
・調べる手段
・PHP用のライブラリ
・1文字ずつ文字コードを調べる場合、なにをもって日本語として判断してよいのか?(文字コード表サイトのURLとか希望)

※プログラミングの中で利用します。ロジックならプログラム言語問わず。ライブラリならPHP用のものでお願いいたします。

回答の条件
  • 1人2回まで
  • 登録:2008/05/04 23:31:48
  • 終了:2008/05/10 01:37:04

ベストアンサー

id:espresso3389 No.1

espresso3389回答回数35ベストアンサー獲得回数62008/05/05 02:37:51

ポイント50pt

あまりPHPに詳しくないので、技術資料の提示だけになりますが、

基本的には、UTF-8のままでの文字コード処理は非常に面倒なので、UCS-2(2バイト/文字)あるいは、UCS-4(4バイト/文字)への変換を行ってから、その文字コードが、日本語の文字コードの領域に収まっているかどうかを判断するということになります。しかしながら、実際のところ、感じに関しては、CJK(中国語・日本語・韓国語)統合といわれる、文字コードの共通化がなされているため、感じを見て、日本語なのか、中国語なのかを探るためにはそれなりのデータベースあるいは、アルゴリズムが必要になると思います。従って、普通の場合は、ひらがな、カタカナが含まれているかどうかを調べる方が良いのではないかと思います。

ここで、言葉について若干の説明をしておきますと、UCS-2とUCS-4は、いずれも、Unicodeの文字セットで、UCS-4は、UCS-2のスーパーセットです。つまり、UCS-4はUCS-2を含みます。もともと、Unicodeでは、16bitですべての文字にコードを割り振ろうとしていましたが、全くもって足らなかったので、最終的に、32bitのUCS-4に落ち着いたと考えていればあんまり問題はありません。また、UTF-8は、32bitのUCS-4をそのまま使うとメモリ効率が悪いので、ASCIIの文字を8bitだけでも表現できるようにいろいろと変換をこらしたものです。そのため、日本語の文字に関しては、通常は、1文字が2バイト~3バイトになります。

さて、実際の処理ですが、

1, 1文字ずつUTF-8→UCS-2(あるいは、UCS-4)への変換を行う

2, ひらがな・カタカナの領域に収まっているかどうかのチェック

になります。本来であれば、すべての情報は、http://www.unicode.org/ から手に入れることができるのですが、言葉が若干難しかったり、あるいは、日本語のリソースがないことなどが障壁になる可能性があるので、適当にGoogleで検索した参考になりそうなサイトを挙げておきます。

1に関しては、ビット操作の知識は必要ですが、

UTF-8

http://www.asahi-net.or.jp/~ci5m-nmr/w3/utf-8.html

などがわかりやすいと思われます。

2に関しては、そのままずばり、

http://www.unicode.org/Public/UNIDATA/Blocks.txt

が参考になります。これは、Unicode.org公式のUnicodeのコードブロックについての説明ですが、これを Hiragana, Katakana で検索すれば、

3040..309F; Hiragana
30A0..30FF; Katakana

というのが見つかります。つまり、この範囲の文字コードがひらがな・カタカナに該当するというわけです。

以上、純粋に技術的な資料だけですので、どこまでお役に立てるかは未知数ですが、ご確認いただければと思います。

また、以下は、C++のコードではありますが、UTF-8→UCS-4の変換を行うコードです。上記のビットの説明と併せて見てみると参考になるかもしれません。ロジックはちょっとだけ改良されているので直接の比較は難しいかもしれませんが・・・。

int get_skip_chars(unsigned char chr)
{
  if((chr & 0x80) == 0x00) return 1;
  else if((chr & 0xe0) == 0xc0) return 2;
  else if((chr & 0xf0) == 0xe0) return 3;
  else if((chr & 0xf8) == 0xf0) return 4;
  else if((chr & 0xfc) == 0xf8) return 5;
  else if((chr & 0xfe) == 0xfc) return 6;
}

unsigned int get_UCS4_code(const unsigned char *ptr, int* skip)
{
  const u8 *p = (const u8 *)ptr;
  unsigned int chr = (unsigned int)*p;
  if(chr < 0x80)
  {
    *skip = 1;
    return chr;
  }

  static const unsigned int base[] = {
    0x00000000, 0x00000000, 0x00003080, 0x000E2080,
    0x03C82080, 0xFA082080, 0x82082080};

  int size = get_skip_chars(chr);
  for(int i = 1; i < size; i++)
    chr = (chr << 6) + p[i];

  *skip = size;
  return chr - base[size];
}

int main()
{
  const char* test = "hello, world"; // イメージ的にはここがUTF-8の文字列
  while(*test)
  {
    int skip;
    unsigned int code = get_UCS4_code(test, &skip);
    if(code >= 0x3040 && code <= 0x309f)
      printf("%08X: ひらがな\n", code);
    if(code >= 0x30a0 && code <= 0x30ff)
      printf("%08X: カタカナ\n", code);
    else
      printf("%08X\n", code); // その他
    test += skip;
  }
}
id:tomohiro555

ありがとうございます。とても参考になりました。

>漢字に関しては、CJK(中国語・日本語・韓国語)統合といわれる、文字コードの共通化がなされているため、

>漢字を見て、日本語なのか、中国語なのかを探るためにはそれなりのデータベースあるいは、アルゴリズム

>が必要になると思います。

なるほど!その情報まってました。やはりそうでしたか。

文字コードの範囲判断だけで簡単に実装できないことがわかり、頭を切り替えて考えられそうです。

>従って、普通の場合は、ひらがな、カタカナが含まれているかどうかを調べる方が良いのではないか

それも検討しました。漢字だけの単文テキストも予想されるので今回はその方法をあきらめました。

C++コードありがとうございます。コードを参考にさせていただきコード変換をして、CJKだったら日本語という判断にしてしまおう方法で検討しようと思います。(あとは別途時間を作ってCJK内でJ部分だけ判断可能なようにアルゴリズムかDBを構築を目指したいと思います。)

2008/05/05 03:58:29

その他の回答(2件)

id:espresso3389 No.1

espresso3389回答回数35ベストアンサー獲得回数62008/05/05 02:37:51ここでベストアンサー

ポイント50pt

あまりPHPに詳しくないので、技術資料の提示だけになりますが、

基本的には、UTF-8のままでの文字コード処理は非常に面倒なので、UCS-2(2バイト/文字)あるいは、UCS-4(4バイト/文字)への変換を行ってから、その文字コードが、日本語の文字コードの領域に収まっているかどうかを判断するということになります。しかしながら、実際のところ、感じに関しては、CJK(中国語・日本語・韓国語)統合といわれる、文字コードの共通化がなされているため、感じを見て、日本語なのか、中国語なのかを探るためにはそれなりのデータベースあるいは、アルゴリズムが必要になると思います。従って、普通の場合は、ひらがな、カタカナが含まれているかどうかを調べる方が良いのではないかと思います。

ここで、言葉について若干の説明をしておきますと、UCS-2とUCS-4は、いずれも、Unicodeの文字セットで、UCS-4は、UCS-2のスーパーセットです。つまり、UCS-4はUCS-2を含みます。もともと、Unicodeでは、16bitですべての文字にコードを割り振ろうとしていましたが、全くもって足らなかったので、最終的に、32bitのUCS-4に落ち着いたと考えていればあんまり問題はありません。また、UTF-8は、32bitのUCS-4をそのまま使うとメモリ効率が悪いので、ASCIIの文字を8bitだけでも表現できるようにいろいろと変換をこらしたものです。そのため、日本語の文字に関しては、通常は、1文字が2バイト~3バイトになります。

さて、実際の処理ですが、

1, 1文字ずつUTF-8→UCS-2(あるいは、UCS-4)への変換を行う

2, ひらがな・カタカナの領域に収まっているかどうかのチェック

になります。本来であれば、すべての情報は、http://www.unicode.org/ から手に入れることができるのですが、言葉が若干難しかったり、あるいは、日本語のリソースがないことなどが障壁になる可能性があるので、適当にGoogleで検索した参考になりそうなサイトを挙げておきます。

1に関しては、ビット操作の知識は必要ですが、

UTF-8

http://www.asahi-net.or.jp/~ci5m-nmr/w3/utf-8.html

などがわかりやすいと思われます。

2に関しては、そのままずばり、

http://www.unicode.org/Public/UNIDATA/Blocks.txt

が参考になります。これは、Unicode.org公式のUnicodeのコードブロックについての説明ですが、これを Hiragana, Katakana で検索すれば、

3040..309F; Hiragana
30A0..30FF; Katakana

というのが見つかります。つまり、この範囲の文字コードがひらがな・カタカナに該当するというわけです。

以上、純粋に技術的な資料だけですので、どこまでお役に立てるかは未知数ですが、ご確認いただければと思います。

また、以下は、C++のコードではありますが、UTF-8→UCS-4の変換を行うコードです。上記のビットの説明と併せて見てみると参考になるかもしれません。ロジックはちょっとだけ改良されているので直接の比較は難しいかもしれませんが・・・。

int get_skip_chars(unsigned char chr)
{
  if((chr & 0x80) == 0x00) return 1;
  else if((chr & 0xe0) == 0xc0) return 2;
  else if((chr & 0xf0) == 0xe0) return 3;
  else if((chr & 0xf8) == 0xf0) return 4;
  else if((chr & 0xfc) == 0xf8) return 5;
  else if((chr & 0xfe) == 0xfc) return 6;
}

unsigned int get_UCS4_code(const unsigned char *ptr, int* skip)
{
  const u8 *p = (const u8 *)ptr;
  unsigned int chr = (unsigned int)*p;
  if(chr < 0x80)
  {
    *skip = 1;
    return chr;
  }

  static const unsigned int base[] = {
    0x00000000, 0x00000000, 0x00003080, 0x000E2080,
    0x03C82080, 0xFA082080, 0x82082080};

  int size = get_skip_chars(chr);
  for(int i = 1; i < size; i++)
    chr = (chr << 6) + p[i];

  *skip = size;
  return chr - base[size];
}

int main()
{
  const char* test = "hello, world"; // イメージ的にはここがUTF-8の文字列
  while(*test)
  {
    int skip;
    unsigned int code = get_UCS4_code(test, &skip);
    if(code >= 0x3040 && code <= 0x309f)
      printf("%08X: ひらがな\n", code);
    if(code >= 0x30a0 && code <= 0x30ff)
      printf("%08X: カタカナ\n", code);
    else
      printf("%08X\n", code); // その他
    test += skip;
  }
}
id:tomohiro555

ありがとうございます。とても参考になりました。

>漢字に関しては、CJK(中国語・日本語・韓国語)統合といわれる、文字コードの共通化がなされているため、

>漢字を見て、日本語なのか、中国語なのかを探るためにはそれなりのデータベースあるいは、アルゴリズム

>が必要になると思います。

なるほど!その情報まってました。やはりそうでしたか。

文字コードの範囲判断だけで簡単に実装できないことがわかり、頭を切り替えて考えられそうです。

>従って、普通の場合は、ひらがな、カタカナが含まれているかどうかを調べる方が良いのではないか

それも検討しました。漢字だけの単文テキストも予想されるので今回はその方法をあきらめました。

C++コードありがとうございます。コードを参考にさせていただきコード変換をして、CJKだったら日本語という判断にしてしまおう方法で検討しようと思います。(あとは別途時間を作ってCJK内でJ部分だけ判断可能なようにアルゴリズムかDBを構築を目指したいと思います。)

2008/05/05 03:58:29
id:sterwars22 No.2

sterwars22回答回数363ベストアンサー獲得回数02008/05/05 08:13:16

ポイント15pt

このライブラリを参考にされればよいのではないでしょうか。

Qdmail

http://www.cpa-lab.com/tech/0127

id:tomohiro555

ありがとうございます。

|

ソースをDLして読んでみました「日本語メールを文字化けせずに送れる」というライブラリのようですが、自分が探している「言語を判別する」でなく「文字コードを判別する」なので参考になりませんでした。(自分がソースを読み切れてないだけかもしれませんが・・とほほ)

>設定次第では、日本語だけでなく各国語対応ができる(はず)

とライブラリのHPには書かれているので期待したのですが、「設定次第で他の文字コードも使えます」の感じで言語判断ではなく、文字コード判断のようでした。

2008/05/06 16:54:59
id:maimi09 No.3

まいみ09回答回数25ベストアンサー獲得回数22008/05/06 13:24:39

ポイント30pt

CJK統合漢字を用いた文章から、日本語で記述されてある可能性について考察するならば「送りがな」に注目するとヨサゲなことが、オライリーの日本語情報処理で指摘されています。

日本語情報処理の新しい版はCJKV日中韓越情報処理になります。(情報が古いかなぁ。)

余談ですが・・・

高性能なプロセッサがメモリにアクセスできる境界を考えるならば、奇数番地にアクセスさせるようなデータを多用するのは非効率的な処理です。ラテン文字を8ビット長に最適化するのは8ビットマイコンなど処理能力の低い小規模なターゲットには有効でも、32ビットマイコンなど処理能力の高く規模の大きいターゲットに対しては懐疑的だと思います。コンパイラのオプションでデータの境界を合わせる最適化をすると、メモリ効率を考えて「ラテン文字を8ビット長にする」のは無駄な努力ともいえそうです。

もちろんプロセッサの処理能力よりも、ストリームの通信コストが高いと判断できる場合は、UTF-8みたいな「ラテン文字を8ビット長に最適化する」べきでしょうけど。

また、xyzzyのメールで教えていただいたのですが、多国語文章できちんと文字の再現ができるエンコーディングは「UTF-8Nぐらいしか存在しない。」そうです。

id:tomohiro555

>CJK統合漢字を用いた文章から、日本語で記述されてある可能性について考察するならば「送りがな」

>に注目するとヨサゲなことが、オライリーの日本語情報処理で指摘されています

なんですと!気になる。読んでおきたいですね。

日本語情報処理、CJKV日中韓越情報処理、共に是非読みたいと思います。(CJKV日中韓越情報処理、高い。><)

>高性能なプロセッサがメモリに 〜省略〜

高性能なのに、悲しい話ですね。

知的好奇心的な部分があるので、実装までやって実用に耐えれるスピードがでなかったらまた別の方法を探そうと思います。

ありがとうございました。

2008/05/06 16:54:30
  • id:tomohiro555
    ■質問内容の補足

    実現したい処理のイメージとして
    ・文字コードUTF-8のテキストファイルが膨大にたくさんある
    ・テキストファイルには、英語、日本語、中国語、ハングル、ロシア語、アラビア語などいろいろな言語で書かれている
    ・単なるテキストファイルなので、ランゲージコードなどは記述されていない
    ・テキストファイル内に日本語が書かれているファイルだけを取り出したい
    といったことを実現する方法を探しております。
  • id:maimi09
    本を入手する予算確保が難しい場合は、とりあえず[http://books.google.co.jp/:title=Google ブック検索]からの立ち読みで我慢する。

    -じつはOCRでインデックスが作られている本もあるよで、キーワードで本の内容が横断検索できたりする。ある意味では、本屋さんでの立ち読みよりも効率的かもしれない。
    -Google ブック検索では、全てのページが読めるわけではない。ある一部分だけである。
    -「日本語情報処理」のように、訳あって本屋で売っていない本も閲覧できる。
    -大きい書店に出向いても「情報科学と数学の専門書は置いてない。」と、お嘆きの方も立ち読みできる。
  • id:espresso3389
    maimi09に反論するつもりはありませんが、UTF-8が高性能なCPUではうんぬんの話ですが、あくまでも効率性の問題であって、あまり本質的ではないので考える必要はないと思いますよ。ミスアラインメントの問題は確かにあるでしょうけど、どうせ、前後の文字列の処理を続けて行うわけで、現実的には特に問題にならないと思います。後で、試しにベンチマークしてみようかな。

    むしろ、プログラミングの効率を考えたときに、UTF-8の扱いが面倒ということはありますから、そういう意味で、一度、32bit整数型の配列にUCS-4のコードとして展開することはあるでしょうね。

    送りがなの件ですが、特に難しい話ではなく、漢字の後にひらがながきているかどうかという判別を行うだけですね。特にCJKV日中韓越情報処理を探して読むまでもないかもしれません。本屋で立ち読みするだけにも重いし。まぁ、この本は、まるで小学生向けの国語の教科書というようなところから始まり、最後の方は結構ディープな話まであるので、読み物としてはおもしろいかもしれません。
  • id:espresso3389
    先ほどのコメントで、maimi09さんに敬称を付けるのを忘れ、呼び捨てになっていました。ここにお詫びいたします。
  • id:tomohiro555
    espresso3389さん、sterwars22さん、maimi09さん
    回答ありがとうございました。

    一旦は、
    1.半角英数記号データのみなら日本語以外と判断
    2.ひらがなやかたかなを含んでいれば日本語と判断
    3.CJK統合を含んでいれば日本語と判断 ※1
    4.上記以外は日本語以外と判断

    ※1:実装後テストし、ゴミデータ(CJK統合だけど日本語じゃない)がおおければ細かいアルゴリズムを入れる。

    で実装しようと思います。
    PHPソースが出来たらコメントで報告します。

この質問への反応(ブックマークコメント)

トラックバック

  • UTF-8テキストの簡易日本語判定 UTF-8で保存されたテキストの日本語判定をする必要があったので,そのメモ. 参考にしたのは,文字コードUTF-8の多言語を含むテキストデータの中に日本語を
「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

絞り込み :
はてなココの「ともだち」を表示します。
回答リクエストを送信したユーザーはいません