新しいフォルダー(1)

メモです。よろしくおねがいします。

[文字コード] 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

次に, 62042Unicodeスカラ値と挿入位置を計算する.

// Unicodeスカラ値の計算
n = 128
n += 62042 / 3
n = 20808 = U+5148 = 先

// 挿入位置の計算
62042 mod 3 = 2

この計算から, nが「先」の文字コードで挿入位置が2であることが分かったため,

添字 文字
0 3
1 B
2

となる.

次に, 139Unicodeスカラ値と挿入位置を計算する.

// Unicodeスカラ値の計算
n += (((2 + 1) + 139) / 4)
n = 20808 + 35
n = 20843 = U+516B = 八

// 挿入位置の計算
((2 + 1) + 139) / 4 = 2

このとき, (((2 + 1) + 139) / 4)における262042 mod 3 = 22で, 1は処理上加算される値である.

この計算から, nが「八」の文字コードで挿入位置が2であることが分かったため,

添字 文字
0 3
1 B
2
3

となる.

続く16683, 34821, 14592, 42088Unicodeスカラ値と挿入位置も同様の計算方法によって求められる.

エンコード手順

3年B組金八先生』を例にエンコードを行う.

最終的なエンコード結果は"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となる.