枚舉變量
base = 36 tmin = 1 tmax = 26(閾值) skew = 38 damp = 70 initial_bias = 72 initial_n =128(0x80 ) delimiter = 0x2d(分隔符 -)
basic (cp) 判斷是不是基本字符,即ASCII以內字符
delim(cp) 判斷是不是 “-”符號
decode_digit(cp)將punycode 36進制數轉換成整數
encode_digit (d,flag) 將字符轉換成 0..25代表字面,26..35表示數字
maxint = -1
adapt (delta,numpoints,firsttime) delta 是增量,numpoints是當前所有已編碼的碼位數量
可變長整數:
傳統的可變長整數,如,100,2983等等等,但是,這些可變長整數一旦連接在一起,1002983,則不能知道兩個整數的界限了,於是,要構造一個新的可變長整數格式:
每一位有一個閾值,t(j)
恰好只有一個權重最大的digit_j<t(j),從而可以區分各個數。
如,734251….. 對應的閾值爲,2,3,5,5,5,5….
因爲7>2,3=3,2<5,所以,2就是那個權重最大的digit,因此,734是一個數,類推,只,251是一個數。
這裏,可以將734,251理解成punycode編碼後的值,只需要將其解碼:各位數,乘以各自權重求和,就可以得到對應的Unicode,從而得到對應的漢子。
權重公式如下:
W(0) = 1
W (j) = w( j-1 ) * (base - t(j-1) ) 當j>0時
閾值公式如下:
t(j) = base * ( j+1 ) – bias
如果計算出t(j) 小於tmin,則t(j) = tmin, 大於tmax 則 t(j) = tmax
Bias 的值是根據貝葉斯調製而得:
1. 爲了避免下步操作數據溢出,堆會按照比例縮小
第一次縮小,delta= delta/damp
第二次及以後,delta= delta/2
2. 堆的增加補償了下個堆會被放入更長的字符串裏:
Delta = delta + (delta/numpoints)
3.堆不斷減小,直到落入界限值
for (k = 0; delta > ((base - tmin) * tmax) / 2; k += base)
{
delta /= base - tmin;
}
4.得到bias 的值
k + (base - tmin + 1) * delta / (delta + skew);
相反的過程,就是編碼過程,編碼過程,就是將Unicode差值,編碼成可變長整數的過程,而這個可變長整數的取值範圍是a~z,0~9的36進制。
編碼步驟:
1. 基礎碼分離:先掃描全部輸入,將ASCII部分,按照原來的次序排在前面的部分,插入‘-’用以分離
2. 把字按Unicode大小遞增排序
3. 計算相鄰Unicode碼差值
4. 差值乘以初始碼位置序號+排序後序號,得到增量
5. 對得到增量編碼成base-36編碼
6. 處理所有增量
如“中國互聯網網絡中心!”
變量初始值
n=initial_n = 128
delta = 0
bias = initial_bias = 72
h = out(out爲輸出字符串當前輸出的位置,由於字符串中有!,所以,目前的h=out= 1)
對應的Unicode 爲
20013 22269 20114 32852 32593 32593 32476 20013 24515 33
除去對‘!’處理,現在看對中文編碼部分
參數m記錄當前Unicode最小值,n代表上一個最小的Unicode值,因爲‘ 國’的Unicode編碼值大於‘中’字,所以,先對‘中’進行處理 (下面過程不考慮報錯情況)
所以,當前
m= 20013 n = 128
對應的delta = (m-n)*(h+1) = 39770
這個過程之後,n=m,爲下一次計算差值做好準備。
Punycode所要編碼的項目,則就是這個delta值,即,後一個字符與前一個字符的Unicode數值之差。
接下來是編碼過程,編碼過程是將39770由地位向高位一位一位的編碼成一個可變長整數的過程。
先以十進制爲例,如816這個數,要求出各位數值,則得從低位開始計算,816%10 = 6 則得出,低位的第一位是6,然後,816/10 =81, 81%10=1,則其次低位爲1,再之,81/10=8, 8%10 = 8 ,則最高位爲8
下面的代碼則是針對base_36 做相同的操作
for (q = delta, k = base;; k += base)
{
if (out >= max_out)
return punycode_big_output;
t = k <= bias /* + tmin */ ? tmin : /* +tmin not needed */
k >= bias + tmax ? tmax : k - bias;
if (q < t)
break;
output[out++] = encode_digit (t + (q - t) % (base - t), 0);
q = (q - t) / (base - t);
}
output[out++] = encode_digit (q, case_flags && case_flags[j]);
bias = adapt (delta, h + 1, h == b);
首先計算低位的閾值,閾值的公式是
t = base*(j+1)-bias
而如果t大於tmax,則t=tmax,反之,t= tmin
j表示當前的位數,從0增長
bias,初始值爲initial_bias = 72
第一次,t + (q - t) % (base - t) 可以得出 最低位 爲 10 經過編碼成base_36 對應字符爲 k
只要q>t ,則表明,仍然是 39770這個數在編碼
繼而得到,其他位爲 16 , 32 , 0
對應編碼爲 q , 6 ,a
所以,第一個字的編碼 爲 kq6a
以此類圖,可以得到全部的編碼信息。
可以驗證,對於 39770這個數
權值
因爲
W(0) = 1
W(j) = w(j-1)*(base – t (j-1) )
w(0) =1
w (1)= w (0) * (36 - 1) = 35
w (2) = w(1)*(36-1) =352
w (3) = w (2) * (36 - 1) = 353
而,39770 = 0 * 353 + 32*352 + 16*35 +10 * 1