距離上次 「-Base62x 新增 -Perl 版本技術實現 Base62x.pm (-R/J2SL )」, Base62x 在時隔 6 個月後又進行了一些更新,記錄一下,也再次印證,最好的版本永遠是下一個版本。此次的更新包括:1)對解碼算法的優化改進;2)增長Python版本的Base62x的工程實現。
php
春節一過即開工,因着技術項目需求,最近加緊編程開發了 Base62x in Python 的版本(Base62x.py)。 Python.py 版本的 Base62x 調用方法大體以下:算法
# import Base62x.py
from Base62x import Base62xnpm# initialize
base62x = Base62x();編程rawstr = 「abcd1234x’efg89;01」;
encstr = base62x.encode(rawstr);
decstr = base62x.decode(encstr);安全
Python 對面向對象的支持較好,因此直接以 OOP 方式編制了 Base62x.py , 並無像 Base62x in Perl版本那樣提供了 OOP 和 functional 兩種方式。網絡
截至目前Base62x 已經開源的編程語言版本以下: C, Java, JavaScript, PHP, Perl 和 Python. 其中 PHP的提供了三個版本:1)以PHP擴展模塊形式的 ext/base62x C語言代碼; 2) PHP 5版本的 Base62x.class.php; 3)PHP 7 版本的 Base62x.class.php 。
其中JavaScript 還有兩個實現, Base62x.class.js 和 npm base62x 。app
在實施 Base62x in Python 的編碼時,咱們發現 Python 語言中沒有提供對自增+1的操做符 「i++」 這樣的操做,而在此前全部版本的 Base62x 的算法中,均大量使用了 「i++」 或者 「++i」 的操做。編程語言
面對這樣的編程語言的特性,咱們不得不尋求另外的實現方法,這既是一種挑戰,彷佛也是一種機遇,咱們在下面的一節討論由此引起的對 Base62x 解碼(decode)的優化改進。 ide
2.1. 改進 if-else 順序
將最大可能的 if 放最前面,減小每次 loop 時的運算對比次數。
改進後的代碼大體以下:函數
if( a > 2){
# most case
}
else if(a == 2){
# secondary most case
}
else{
# least case
}
改進後,有望減小計算判斷,提高程序運行速度。也即若是按照一般的邏輯,若是代碼寫成 if(a==1){ … }else if(a==2){ … }else if(a>2){ … }, 則在每個循環中,程序都要拿 a 跟 1, 2, 3等各個分支比對一次,而後再進入所對應的分支塊。這是本次改進的主要認識之一。
2.2. 改進對自增操做符 i++ 等的調用
使用內部子循環來優化解碼(decode)操做, 減掉大量循環體內的 if-else 操做,減掉 ++i 和 ++m 的操做.
如前所述,咱們在編碼 Base62x in Python 時,發現 Python 沒法提供相似 「i++」 或者 「++i」 自增操做符,而在 Base62x 以前的不少版本的解碼操做中,均有大量使用自增操做符。原算法的代碼大體以下 (C語言):
switch(remaini){
case 1:
printf(「Base62x.decode: found illegal base62x input:[%s]! 1612121816.\n」, input);
break;case 2:
if(input[i]==xtag){ tmpin[0] = bpos+bint[input[++i]]; }
else{ tmpin[0]=rb62x[input[i]]; }
if(i == maxidx){ //- may be wrapped into a func decode_by_length
c0 = (tmpin[0] << 2);
output[m]=c0;
}
else{
if(input[++i]==xtag){ tmpin[1] = bpos+bint[input[++i]]; }
else{ tmpin[1]=rb62x[input[i]]; }
c0 = tmpin[0] << 2 | tmpin[1];
output[m]=c0;
}
break;case 3:
if(input[i]==xtag){ tmpin[0] = bpos+bint[input[++i]]; }
else{ tmpin[0]=rb62x[input[i]]; }
if(input[++i]==xtag){ tmpin[1] = bpos+bint[input[++i]]; }
else{ tmpin[1]=rb62x[input[i]]; }
if(i == maxidx){
c0 = tmpin[0] << 2 | tmpin[1];
output[m]=c0;
}
else{
if(input[++i]==xtag){ tmpin[2] = bpos+bint[input[++i]]; }
else{ tmpin[2]=rb62x[input[i]]; }
c0 = tmpin[0] << 2 | tmpin[1] >> 4;
c1 = ( ( tmpin[1] << 4) & 0xf0) | tmpin[2];
output[m]=c0;
output[++m]=c1;
}
break;default:
if(i < last8){
if( input[i]==xtag){ tmpin[0] = bpos+bint[input[++i]]; }
else{ tmpin[0]=rb62x[input[i]]; }
if( input[++i]==xtag){ tmpin[1] = bpos+bint[input[++i]]; }
else{ tmpin[1]=rb62x[input[i]]; }
if( input[++i]==xtag){ tmpin[2] = bpos+bint[input[++i]]; }
else{ tmpin[2]=rb62x[input[i]]; }
if( input[++i]==xtag){ tmpin[3] = bpos+bint[input[++i]]; }
else{ tmpin[3]=rb62x[input[i]]; }
c0 = tmpin[0] << 2 | tmpin[1] >> 4;
c1 = ( ( tmpin[1] << 4) & 0xf0) | ( tmpin[2] >> 2 );
c2 = ( ( tmpin[2] << 6) & 0xff) | tmpin[3];
output[m]=c0;
output[++m]=c1;
output[++m]=c2;
}
else{
if(input[i]==xtag){ tmpin[0] = bpos+bint[input[++i]]; }
else{ tmpin[0]=rb62x[input[i]]; }
if(input[++i]==xtag){ tmpin[1] = bpos+bint[input[++i]]; }
else{ tmpin[1]=rb62x[input[i]]; }
if(i == maxidx){
c0 = tmpin[0] << 2 | tmpin[1];
output[m]=c0;
}
else{
if(input[++i]==xtag){ tmpin[2] = bpos+bint[input[++i]]; }
else{ tmpin[2]=rb62x[input[i]]; }
if(i == maxidx){
c0 = tmpin[0] << 2 | tmpin[1] >> 4;
c1 = ( ( tmpin[1] << 4) & 0xf0) | tmpin[2];
output[m]=c0;
output[++m]=c1;
}
else{
if(input[++i]==xtag){ tmpin[3] = bpos+bint[input[++i]]; }
else{ tmpin[3]=rb62x[input[i]]; }
c0 = tmpin[0] << 2 | tmpin[1] >> 4;
c1 = ( ( tmpin[1] << 4) & 0xf0) | ( tmpin[2] >> 2 );
c2 = ( ( tmpin[2] << 6) & 0xff) | tmpin[3];
output[m]=c0;
output[++m]=c1;
output[++m]=c2;
}
}
}
}
變量 remaini 是當前待處理的字符流的餘量,算法的邏輯是對餘量按每四個字符進行解碼並按位操做。按餘量不一樣,分別按4,3,2,1的長度狀況使用 switch分別處理。這裏首先要按 2.1. 的思路,將 餘量爲4 (最大可能)放第一位 if,而後再處理 i++ 和 ++m 的狀況。
根據測試實驗,使用一個內部的子循環能夠取代 i++ (++i)和 m++ (++m) 的狀況,針對C語言版本,還實現了此前處於@todo 的 decode_by_length . 該函數是用於處理 C、Java等可能出現的數據越界的安全檢查等。改進後的代碼大幅減小,(C語言)源代碼大體以下:
if(remaini > 1){
j = 0;
do{
if(input[i] == xtag){
i+=1;
tmpin[j] = bpos+bint[input[i]];
}
else{
tmpin[j]=rb62x[input[i]];
}
i+=1; j+=1;
}
while(j < 4 && i < inputlen);
m = decode_by_length(tmpin, output, m);
}
else{ //- == 1
printf(「Base62x.decode: found illegal base62x input:[%s]! 1612121816.\n」, input);
continue;
}
從代碼量上看,改進後的代碼縮減至 10幾行,而優化改進以前的代碼足足有幾十行至上百行,所以不管從體量仍是從邏輯上看,改進後的代碼更高效、簡介。改進優化前: do{ if–else if– else if — else if — else; }while(…), 改進優化後: do{ do{ if — else; }while(…); }while(…); .
2.3. 針對全部已知編程語言版本進行升級改進
將上述在 C語言版本 base62x.c 中的算法,近測試無誤後將相應地算法一樣地在 Java, JavaScript, PHP, Perl 等版本中一一從新實現,並使用所對應的測試腳本對按 2.1 和 2.2 進行優化改進的算法進行測試。
測試結果顯示,修改符合預期,優化改進成功。
另外還完成了 C語言、Java語言版本中的 decodeByLength 內部函數/方法的實現。
3. 持續向前兼容全部 Base62x 版本
上述 2.1. 和 2.2. 的優化改進,是 Base62x 在應用範圍和算法性能上的擴展和改進。這些改進不會對現有的 Base62x 在格式、定於及語法上引發偏誤,改進後的代碼持續向前兼容全部 Base62x 的歷史版本。
也即,此前版本Base62x 編碼出來的 String,可以使用改進後的的算法準確地進行解碼;使用改進版本的Base62x編碼出來的String,也可以使用原來的Base62x算法本來無誤地進行解碼。
Base62x is an alternative approach to Base64 for only alphanumeric characters in output.
Base62x can be used safely in computer file systems, programming languages for data exchange, internet communication systems, and is an ideal substitute and successor of many variants of Base64 encoding scheme.
Base62x 是一種無符號的Base64編碼方案。
Base62x 能夠在計算機文件系統、編程語言數據交換、互聯網絡通訊系統中安全地使用,同時是各類變種Base64編碼方案的理想替代品、繼任者。