[文字コード] Punycode
Punycode
Punycode(ピュニコード, プニコード)とは, 国際化ドメイン名で使用されるエンコーディング方式で, RFC 3492で定義され, RFC 5891で更新されている.
Adam M. Costello氏によって考案され, 仮称はAMC-ACE-Zであった.
ASCII文字で対応できる文字をそのまま利用することで全体的な文字数を減らす努力がなされている.
また, Base64などに比べ高い圧縮率のエンコーディング方式である.
デコード手順
xn--3B-ww4c5e180e575a65lsy2b
を例にデコードを行う.
最終的なデコード結果は『3年B組金八先生』となる.
1. 接頭辞を取る
Punycodeでエンコードされた文字列は接頭辞としてxn--
が付加されるため, デコード時にはこれを取り外す.
xn--3B-ww4c5e180e575a65lsy2b
-> 3B-ww4c5e180e575a65lsy2b
2. ASCII文字とマルチバイト文字を分ける
3B-ww4c5e180e575a65lsy2b
の内, -(ハイフン)よりも前の文字はASCII文字であるため, デコードの対象にならない.
3B-ww4c5e180e575a65lsy2b
-> ww4c5e180e575a65lsy2b
3. デコード処理
ww4c5e180e575a65lsy2b
の部分は一般化可変長整数と呼ばれる仕組みでエンコードされているため, これを通常の10進数に戻す.
ww4c5e180e575a65lsy2b
-> 62042
, 139
, 16683
, 34821
, 14592
, 42088
次に, 62042
のUnicodeスカラ値と挿入位置を計算する.
// Unicodeスカラ値の計算 n = 128 n += 62042 / 3 n = 20808 = U+5148 = 先 // 挿入位置の計算 62042 mod 3 = 2
この計算から, nが「先」の文字コードで挿入位置が2であることが分かったため,
添字 | 文字 |
---|---|
0 | 3 |
1 | B |
2 | 先 |
となる.
次に, 139
のUnicodeスカラ値と挿入位置を計算する.
// Unicodeスカラ値の計算 n += (((2 + 1) + 139) / 4) n = 20808 + 35 n = 20843 = U+516B = 八 // 挿入位置の計算 ((2 + 1) + 139) / 4 = 2
このとき, (((2 + 1) + 139) / 4)
における2
は62042 mod 3 = 2
の2
で, 1
は処理上加算される値である.
この計算から, nが「八」の文字コードで挿入位置が2であることが分かったため,
添字 | 文字 |
---|---|
0 | 3 |
1 | B |
2 | 八 |
3 | 先 |
となる.
続く16683
, 34821
, 14592
, 42088
のUnicodeスカラ値と挿入位置も同様の計算方法によって求められる.
エンコード手順
最終的なエンコード結果は"xn--3B-ww4c5e180e575a65lsy2b"となる.
1. 数値化する
文字 | 16進数表記 | 10進数表記 |
---|---|---|
3 | U+0033 | 51 |
年 | U+5E74 | 24180 |
B | U+0042 | 66 |
組 | U+7D44 | 32068 |
金 | U+91D1 | 37329 |
八 | U+516B | 20843 |
先 | U+5148 | 20808 |
生 | U+751F | 29983 |
2. ASCII文字とマルチバイト文字を分ける
文字 | 16進数表記 | 10進数表記 |
---|---|---|
3 | U+0033 | 51 |
B | U+0042 | 66 |
文字 | 16進数表記 | 10進数表記 |
---|---|---|
年 | U+5E74 | 24180 |
組 | U+7D44 | 32068 |
金 | U+91D1 | 37329 |
八 | U+516B | 20843 |
先 | U+5148 | 20808 |
生 | U+751F | 29983 |
3. マルチバイト文字をUnicodeスカラ値順に昇順ソートする
文字 | 16進数表記 | 10進数表記 |
---|---|---|
先 | U+5148 | 20808 |
八 | U+516B | 20843 |
年 | U+5E74 | 24180 |
生 | U+751F | 29983 |
組 | U+7D44 | 32068 |
金 | U+91D1 | 37329 |
4. エンコード処理
delta, n, m, c, hの5つの変数を用いる.
- delta: 各Unicodeスカラ値のエンコード後の値を格納する変数
- n: 次のソートされたUnicodeスカラ値を格納するときに現在のUnicodeスカラ値を格納しておく変数
- m: ソートされたUnicodeスカラ値を順に格納する変数
- c: ソート前のUnicodeスカラ値を順に格納する変数
- h: 何文字目の処理かを格納する変数
なお, deltaの初期値は0であるが, ソート後のUnicodeスカラ値を選択したときにdelta += (m - n) * h
が格納される.
また, nの初期値は128
である.
hの初期値は今回の場合,
添字 | 文字 |
---|---|
0 | 3 |
1 | B |
のように0文字目と1文字目はすでに決まっているので2が格納される.
// 初期化 n = 128 h = 2 delta = 0 // deltaの計算 h++ delta += (m - n) * h delta += (20808 - 128) * 3 delta = 62040 // nの計算 n += 1 n = 20809
次にソート前のUnicodeスカラ値の並びである51
, 24180
, 66
, 32068
, 37329
, 20843
, 20808
, 29983
とソート後のUnicodeスカラ値の1つ目である20808
を順に比較する.
文字 | 10進数表記 | 比較 | 比較対象「先」 | delta | h |
---|---|---|---|---|---|
3 | 51 | < | 20808 | 62041 | 3 |
年 | 24180 | > | 20808 | 62041 | 3 |
B | 66 | < | 20808 | 62042 | 3 |
組 | 32068 | > | 20808 | 62042 | 3 |
金 | 37329 | > | 20808 | 62042 | 3 |
八 | 20843 | > | 20808 | 62042 | 3 |
先 | 20808 | = | 20808 | 0 | 4 |
生 | 29983 | > | 20808 | 0 | 4 |
// deltaの計算 delta = (m - n) * h delta += (20843 - 20809) * 4 delta = 137 // nの計算 n += 1 n = 20844
先と同じように比較する.
文字 | 10進数表記 | 比較 | 比較対象「先」 | delta | h |
---|---|---|---|---|---|
3 | 51 | < | 20843 | 138 | 4 |
年 | 24180 | > | 20843 | 138 | 4 |
B | 66 | < | 20843 | 139 | 4 |
組 | 32068 | > | 20843 | 139 | 4 |
金 | 37329 | > | 20843 | 139 | 4 |
八 | 20843 | = | 20843 | 0 | 5 |
先 | 20808 | < | 20843 | 1 | 5 |
生 | 29983 | > | 20808 | 1 | 5 |
同様にdelta
の計算を続けると, 最終的に62042
, 139
, 16683
, 34821
, 14592
, 42088
となる.
これに一般化可変長引数の仕組みを利用して変換し, 接頭辞と3B
を繋げると, xn--3B-ww4c5e180e575a65lsy2b
となる.