Punycode

（ピュニコード、プニコード）とは、国際化ドメイン名で使われる文字符号化方式で、 で定義されている。 で書かれた文字列をDNSで使用可能な、アルファベット（大文字小文字を区別しない）、数字、ハイフンのみの文字列に変換する。

概要
ドメイン名として  を使用する際は、ピリオド（.）で区切られたドメイン名の階層レベルごとにプレフィックスとして「xn--」を使用し、エンコードされた文字列を続ける。大文字と小文字は区別されない。

エンコーディング手順
この節では、  のエンコーディング手順を、「」がどのようにして「bcher-kva」と変換されるかを例にとって、説明する。

文字の分離 
最初に、入力文字列中にあるすべてのASCII文字を残し、ASCII文字以外の文字を取り去る。また、ASCII文字以外の文字がある場合は、最後に区切り文字（ハイフン、 -）を追加する。

非文字の挿入をコード番号としてエンコード 
次のエンコーディング手順を理解するために、先にデコーダの動作を理解する必要がある。

デコーダは、2つの状態変数 i と n を持つオートマトンである。 i は分離した後のASCII文字列への挿入位置を表し、その範囲は0 (文字列の先頭への挿入を表す) からASCII文字列の長さ (文字列の末尾への挿入を表す) である。従って、この例では0–5となる。nは挿入する文字のコードポイントである。

i は0から始まり、n は128 (非ASCII文字の最初のコードポイント) から始まる。状態遷移は単調であり、遷移すると i が1だけ増加する。ただし i がすでに最大値の場合は n が1増加し、i は0に戻る。つまり、挿入するべき箇所がなくなると、挿入すべき文字が1つ後の物となる。要するに、各状態遷移の際、nで表されるコードポイントを文字列に挿入するか、挿入をスキップするか、という動きとなる。

コード番号は、エンコーダによって生成される数値であり、デコーダが文字を挿入する前にスキップすべき挿入可能位置がいくつあるかを数値化したものである。"ü" のUnicodeコードポイントはU+00FC, 10進数で表すと252である。よって、ü の字を文字列の1文字目の後ろに挿入するには、ü より前にある124 (251 - 127 = 124) 種類の非ASCII文字が、"bcher" の中に6か所ある挿入ポイントに挿入されるのをスキップし、さらに0文字目 (つまり文字列の先頭) にüが挿入されるのをスキップする必要がある。したがって、デコーダには必要な1文字を挿入するために、(124 × 6) + 1 = 745回の非ASCII文字挿入をスキップするようデコーダに伝える必要がある。

コード番号をASCII文字列として再変換 

Punycode は、このコード番号を表すためにリトルエンディアンの一般化可変長整数を使用する。例として、コード番号745を「kva」と表す方法を示す。

一般化可変長整数では、各々の桁に異なる閾値を設け、これより小さい数字の表れる桁を最大桁とすることで、数字列の区切りを決める。 Punycode で用いられるリトルエンディアンの場合、小さい桁から表記されるため、先読みなしで任意の桁数の数字を表記できる。

Punycode の場合は、各桁に使える数字として36種の文字を使用する。アルファベット（大文字小文字を区別しない）の'a'から'z'が0から25を表し、数字の'0'から'9'が26から35を表す (このため、後述する式に出てくる底 (base) は、36となる)。

したがって、「kva」は「10 21 0」を表す。ここで閾値は (1 1 26) であるとする。最初の桁 (kつまり10) の重みは1である。1桁目は1–35までの範囲の値をとるため、2桁目 (vつまり21) の重みは35となる。2桁目は同様に1–35の範囲の値をとるため、3桁目 (aつまり0) の重みは 352 = 1225 である。また、3桁目の値0は3桁目の閾値26よりも小さいため、ここで1つ目の数字列は終了であることがわかる。したがって「kva」は 10 × 1 + 21 × 35 + 0 × 1225 = 745 を表していることがわかる。

各桁の重みw(j)および閾値t(j)の値は、以下の式で計算される:
 
 
 
（ただしt(j)は上式をtmin以下ならtmin、tmax以上ならtmaxとクランプしたものである。 bias は状態変数である。）
 base = 36, tmin = 1, tmax = 26

2つ目の文字を挿入する際には、さらにエンコードされたコード番号を繋げていけばよいが、挿入のたびにbiasの値が調節され、各桁の閾値と重みが変わることに注意する必要がある。biasの値が変わらない範囲であれば、単純に追加するだけでよい。例えば、"bücher" に2つ目の非ASCII文字を挿入しようとすると、前述のとおりデコーダは前に戻れないため、最初の挿入結果は "büücher" で、コードは "bcher-kvaa" となる。次の挿入可能位置は "bücüher" で "bcher-kvab" となる。同様に、続きの "bücherü" は "bcher-kvae" となり、次に来るのは "ýbücher" で "bcher-kvaf" である。

脚注

関連項目 
国際化ドメイン名

外部サイト 
 
 Online Punycode/IDN Decoder/Encoder
 IDN Library—Libidn
 ICU IDNA Demonstration An online demonstration of how ICU performs IDN operations
 Punycode for Domains Convert Unicode to Punycode
 List of TLDs considered by the Mozilla developers to have an effective anti-spoofing policy for name registration
 日本語JPドメイン名のPunycode変換・逆変換 - 日本語.jp
 Punycoder - the Punycode converter (IDN converter) 🔧

Unicode
国際化ドメイン名
3492