Rubyならeach_charでいいんでしょうが、C++でそれと同じようなことをしようと思ったらよく分からなかったので。WEB+DB PRESS Vol.53のp108付近(検索エンジンのところ)のことをやりたかった。
キモは
(byte & 0xC0) == 0x80
の部分で
まずUTF-8の符号方式では、2バイトめ以降は先頭2ビットが10で始まるという事実を利用し、まず各バイトがUTF-8の先頭かどうかを判定し((buf[i] & 0xC0) == 0x80)、その場合はそれらがタームであるとしparsedに追加をしていきます。
と説明がされている。
ゆとりなおいらにはビット演算が色々分かってないので、その辺から勉強しないといけない。0xC0というのは11000000を16進数で書いたもの。"&"と"&&"は全然違って、"&"はビット積となる。例えば、11100011と11000000のビット積を取ると11000000となる(両方1のところだけ生き残る)。最後にこのビット積が0x80(2進数だと10000000)と等しいかを比べる。この場合だと等しくなく、先頭の文字だと判定できる(ビット積が0x80になっていると先頭ではないと分かる)。
他のケースとして、例えば
- 10100011と11000000 => 10000000
- 0x80となり先頭ではない
- 11100011と11000000 => 11000000
- 0x80ではないので先頭
- 01100011と11000000 => 01000000
- 0x80ではないので先頭(でいいのか?)
- 10100011と11000000 => 10000000
- 0x80となり先頭ではない
というのがあって、どれも10から始まるものは先頭にできている。「0xC0とのビット積を取って、0x80と等しいかを見る」という操作と「元のビットの先頭が10で始まっているかを見る」という操作が対応していることが分かる(!!)。
# -*- coding: utf-8 -*- str = "abあい" s = String.new chars = [] first = true (0..str.bytesize-1).each{|i| byte = str.getbyte(i) template = "#{byte.to_s(2)}(#{byte}) & #{0xC0.to_s(2)}(0xC0) => #{(byte & 0xC0).to_s(2)} equals #{0x80.to_s(2)}?" if (first || (i != str.bytesize && (byte & 0xC0) == 0x80)) puts "#{template} => yes!!" # 先頭ではないケース s << byte first = false next end puts "#{template} => no!!" # 先頭のケース chars.push s s = String.new break if i == str.bytesize - 1 s << byte } chars.push s puts chars.join(", ")
実行するとこんな感じでUTF-8単位の一文字で分割ができている。
/Users/syou6162/ruby% /opt/local/bin/ruby1.9 bit.rb 1100001(97) & 11000000(0xC0) => 1000000 equals 10000000? => yes!! 1100010(98) & 11000000(0xC0) => 1000000 equals 10000000? => no!! 11100011(227) & 11000000(0xC0) => 11000000 equals 10000000? => no!! 10000001(129) & 11000000(0xC0) => 10000000 equals 10000000? => yes!! 10000010(130) & 11000000(0xC0) => 10000000 equals 10000000? => yes!! 11100011(227) & 11000000(0xC0) => 11000000 equals 10000000? => no!! 10000001(129) & 11000000(0xC0) => 10000000 equals 10000000? => yes!! 10000100(132) & 11000000(0xC0) => 10000000 equals 10000000? => yes!! a, b, あ, い
うおー、基礎がなってないって感じですね。。。

- 作者: Yugui
- 出版社/メーカー: オライリージャパン
- 発売日: 2008/06/26
- メディア: 大型本
- 購入: 27人 クリック: 644回
- この商品を含むブログ (253件) を見る