𪚲 (𪚲)
理屈は 65536 以上(17ビット以上。0,1が17文字以上)の場合、
unicode番号の最大値から 65536 を引くと最大で 20ビット(1が20個。9999のような桁が上がる直前)になるので、
65536 以上の数値を 65536 引いて 10ビットずつの2つに分けて、
0~65535 の内、使われていない範囲を指定する6ビットを、分けた2つのそれぞれの頭につける。
(1文字目の 6ビット) (1文字目の 10ビット) (2文字目の 6ビット) (2文字目の 10ビット)
String.fromCharCode の場合、それを String.fromCharCode(1文字目の16ビット, 2文字目の16ビット) として渡すと1文字を表現できます。
1文字目の10ビット、2文字目の10ビットが変化するので
2^10 * 2^10 = 1,048,576
ということで100万種類ぐらいになると思います。
0 ~ 65535 までは16ビット | |
---|---|
0xFFFF (bin) | 1111111111111111 |
0xFFFF (dec) | 65535 |
0xFFFF (bin, length) | 16 |
65536 以上は17ビット以上 | |
0x10000 (bin) | 10000000000000000 |
0x10000 (dec) | 65536 |
0x10000 (bin, length) | 17 |
unicode の文字数 | |
0x10FFFF (bin) | 100001111111111111111 |
0x10FFFF (dec) | 1114111 |
0x10FFFF (bin, length) | 21 |
65536 を引くと20ビット | |
0x10FFFF - 0x10000 (bin) | 11111111111111111111 |
0x10FFFF - 0x10000 (dec) | 1048575 |
0x10FFFF - 0x10000 (bin, length) | 20 |
num = 0x2A6B2 の場合 | |
String.fromCharCode(0x2a6b2) | 文字化け |
num (bin) | 101010011010110010 |
num (dec) | 173746 |
num (bin, length) | 18 |
# num (hex) | 2a6b2 |
num - 65536 した場合 | |
num - 0x10000 (bin) | 11010011010110010 |
num - 0x10000 (dec) | 108210 |
num - 0x10000 (bin, length) | 17 |
# num - 0x10000 high,low | 1101001,1010110010 |
サロゲートペア1文字目に移動させる値 | |
0xD800 (bin) | 1101100000000000 |
0xD800 (dec) | 55296 |
0xD800 (bin, length) | 16 |
# 0xD800 high,low | 110110,0000000000 |
# 110110 00 00000000 | d800 |
# 110110 01 00000000 | d900 |
# 110110 10 00000000 | da00 |
# 110110 11 00000000 | db00 |
# 110110 11 11111111 | dbff |
サロゲートペア2文字目に移動させる値 | |
0xDC00 (bin) | 1101110000000000 |
0xDC00 (dec) | 56320 |
0xDC00 (bin, length) | 16 |
# 0xDC00 high,low | 110111,0000000000 |
# 110111 00 00000000 | dc00 |
# 110111 01 00000000 | dd00 |
# 110111 10 00000000 | de00 |
# 110111 11 00000000 | df00 |
# 110111 11 11111111 | dfff |
サロゲートペア1文字目 | |
high ((num - 0x10000) >> 10) | 1101001 |
high mask | 1101100000000000 |
high result | 1101100001101001 |
high result (dec) | 55401 |
サロゲートペア2文字目 | |
parseInt("1111111111", 2).toString(16) | 3ff |
low ((num - 0x10000) & 0x3FF) | 1010110010 |
low mask | 1101110000000000 |
low result | 1101111010110010 |
low result (dec) | 57010 |
String.fromCharCode に2つ指定 | |
String.fromCharCode(55401, 57010) | 𪚲 |
この文字設定をサロゲートペアといいます。
http://ja.wikipedia.org/wiki/Unicode%E4%B8%80%E8%A6%A7_D000-DFFF
http://ja.wikipedia.org/wiki/Unicode#.E3.82.B5.E3.83.AD.E3.82.B2.E3.83.BC.E3.83.88.E3.83.9A.E3.82.A2
2進数の 1xxxxxxxxxx >> 10 は 1になります。
// 例. 一桁目が消えて2桁目が1桁目になります。(2で割る。右シフト) alert(parseInt("010", 2) >> 1); // 1 (01) alert(parseInt("100", 2) >> 1); // 2 (10) alert(parseInt("110", 2) >> 1); // 3 (11) alert(parseInt("011", 2) >> 1); // 1 (01) alert(parseInt("101", 2) >> 1); // 2 (10) alert(parseInt("111", 2) >> 1); // 3 (11)
2進数の ??????????xxxxxxxxxx & 0x3FF(2進数で1が10個) は xxxxxxxxxx になります。
// 例. それぞれの桁で両方とも1の場合に、それぞれの桁が1になります。 alert(parseInt("010", 2) & parseInt("001", 2)); // 0 (000) alert(parseInt("100", 2) & parseInt("001", 2)); // 0 (000) alert(parseInt("110", 2) & parseInt("001", 2)); // 0 (000) alert(parseInt("011", 2) & parseInt("001", 2)); // 1 (001) alert(parseInt("101", 2) & parseInt("001", 2)); // 1 (001) alert(parseInt("111", 2) & parseInt("001", 2)); // 1 (001)
high result, low result はオア演算です。
// 例. それぞれの桁でどちらかに1があれば、それぞれの桁を1にします。 alert(parseInt("010", 2) | parseInt("001", 2)); // 3 (011) alert(parseInt("100", 2) | parseInt("001", 2)); // 5 (101) alert(parseInt("110", 2) | parseInt("001", 2)); // 7 (111) alert(parseInt("011", 2) | parseInt("001", 2)); // 3 (011) alert(parseInt("101", 2) | parseInt("001", 2)); // 5 (101) alert(parseInt("111", 2) | parseInt("001", 2)); // 7 (111)
ビット演算子は、他の言語でも同じように記述できる場合が多いです。
http://php.net/manual/ja/language.operators.bitwise.php
2進数、16進数は、理屈がわかっていれば暗算はできなくていいと思います。
buf = ""; buf += "### 0\n"; buf += parseInt("0", 2) + "\n"; // 0 buf += parseInt("0", 10) + "\n"; // 0 buf += parseInt("0", 16) + "\n"; // 0 buf += "### 1\n"; buf += parseInt("1", 2) + "\n"; // 1 buf += parseInt("1", 10) + "\n"; // 1 buf += parseInt("1", 16) + "\n"; // 1 // 2進数の10 = 0 1 10 // 10進数の10 = 0 1 2 3 4 5 6 7 8 9 10 // 16進数の10 = 0 1 2 3 4 5 6 7 8 9 A B C D E F 10 buf += "### それぞれの 10\n"; buf += parseInt("10", 2) + "\n"; // 2 = ( 2 * 1) buf += parseInt("10", 10) + "\n"; // 10 = (10 * 1) buf += parseInt("10", 16) + "\n"; // 16 = (16 * 1) buf += "### それぞれの 11\n"; buf += parseInt("11", 2) + "\n"; // 3 = ( 2 * 1) + 1 buf += parseInt("11", 10) + "\n"; // 11 = (10 * 1) + 1 buf += parseInt("11", 16) + "\n"; // 17 = (16 * 1) + 1 buf += "### 10進数と16進数の 99\n"; buf += parseInt(" 99", 10) + "\n"; // 99 = (10 * 9) + 9 buf += parseInt(" 99", 16) + "\n"; // 153 = (16 * 9) + 9 buf += "### 10進数と16進数の 999\n"; buf += parseInt("999", 10) + "\n"; // 999 = (10 * 10 * 9) + (10 * 9) + 9 buf += parseInt("999", 16) + "\n"; // 2457 = (16 * 16 * 9) + (16 * 9) + 9 buf += "### 16進数の F, FF\n"; buf += parseInt(" F", 16) + "\n"; // 15 = 15 buf += parseInt("FF", 16) + "\n"; // 255 = (16 * 15) + 15 buf += "### 2進数の 1111, 11111111\n"; buf += parseInt(" 1111", 2) + "\n"; // 15 = (2^3*1)+(2^2*1)+(2^1*1)+(2^0*1) buf += parseInt("11111111", 2) + "\n"; // 255 = (2^7*1)+(2^6*1)+(2^5*1)+(2^4*1)+(2^3*1)+(2^2*1)+(2^1*1)+(2^0*1) alert(buf);
他のやり方としては、割り算や、一旦文字列にする(非推薦)、などあります。
一旦文字列にして実行すると意味が理解しやすい場合があります。
ビット演算がやっていることが明確なのと早いそうなので良いです。
var nums, ret, i, num; nums = new Array(0); nums[0] = 0x2a6b2; nums[1] = 0x296F0; nums[2] = 12307; nums[3] = -1; nums[4] = 0; nums[5] = 0x10FFFF; nums[6] = 0x110000; nums[7] = 65535; nums[8] = 65536; ret = ""; for (i = 0; i < nums.length; i++) { if (nums[i] < 0) { ret = "Error"; } else if (nums[i] <= 0xFFFF) { ret = "1: " + String.fromCharCode(nums[i]); } else if (nums[i] <= 0x10FFFF) { num = nums[i]; num -= 0x10000; ret = "2: " + String.fromCharCode((num >> 10) | 0xD800, (num & 0x3FF) | 0xDC00); } else { ret = "Error"; } alert("[" + i + "] " + nums[i] + " = " + ret); }
0x110000 の場合 21桁目が1でその下が全部0の2進数になるので2文字とも 0xDC00 と同じになります。
正式名称は UTF-16BE でいいんだと思います。明確にするためにはBOM無しと記述すればいいのかもしれません。
http://ja.wikipedia.org/wiki/UTF-16
http://liosk.blog103.fc2.com/blog-entry-164.html?sess=83184307bdcf6494ab8d34a228efb8fe
http://en.wikipedia.org/wiki/UTF-16/UCS-2#Example_UTF-16_encoding_procedure
http://unicode.org/Public/UNIDATA/Blocks.txt
0 件のコメント:
コメントを投稿