Base62x算法改进并增长Base62x in Python

距离上次 “-Base62x 新增 -Perl 版本技术实现 Base62x.pm (-R/J2SL )”, Base62x 在时隔 6 个月后又进行了一些更新,记录一下,也再次印证,最好的版本永远是下一个版本。此次的更新包括:1)对解码算法的优化改进;2)增长Python版本的Base62x的工程实现。
php

1. 增长 Base62x in Python

春节一过即开工,因着技术项目需求,最近加紧编程开发了 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. Base62x 解码算法的优化改进

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编码方案的理想替代品、继任者。

 

-R/h2SP 

相关文章
相关标签/搜索