参考护照编码实现算法JS生成带字母有序编码

本文参照护照编码的规则实现类似算法,仅供学习研究使用

 

先看一下护照的编码规则 :

例如:E00000001、E00000002、E00000003...E99999999、EA0000001

 

【规则分析】

可以发现,固定E开头,后面的数字按顺序增加,到达99999999时高位开始变成字母从A开始

也就是说先使用8位数十进制开始顺序编码,十进制数字用完以后由高位至低位逐渐变成36进制(10个数字+26个大写字母)

 

【实现解析】

如果直接使用36进制去编码,显然不对,就会出现 00000A 这样的编码。而需要让字母在高位 必须先使用10进制,10进制用完再改变高位的进制类型,也就是说不同位数使用不同的进制来处理,到达该进制最大值时升级进制。

以下是实现效果和完整的代码,先看效果,再讲解代码:

 

【效果展示】

* 为方便查看结果,使用3位长度测试

图1:开始使用十进制编码

 

 图2:达到十进制最大值999以后高位变成36进制

 

 图3:到达36进制3位数最大值ZZZ后报错

 

 

【代码】

// 不同进制配置
let num36 = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
let num10 = '0123456789';
// val=当前值 ,numList=进制列表(支持不同位使用不同的进制)
function plusOne(val, numList) {
  // 拆分成单个位数,反转后让索引为0的=低位
  let valArr = val.split('').reverse();
  numList.reverse();
  // 指定进制,在当前位的基础上加1位,返回'0'时表示需要向前进一位
  function add(num, cur) {
    let nexIndex = num.indexOf(cur) + 1;
    if (nexIndex === num.length) nexIndex = 0;
    return num[nexIndex];
  }
  // 从低位到高位处理
  for (let i = 0; i < valArr.length; i++) {
    let c = add(numList[i] || num10, valArr[i]);
    valArr[i] = c;
    // 没有达到进位要求
    if (c !== '0') break;
    // 等于0时需要在高一位的位置加1,push增加一个高位
    valArr.push('');
  }
  return valArr.reverse().join('');
}

// 获取当前数值下一个值,限制总位数
function nextVal(curVal, len) {
  // 计算不同位的进制
  let numList = [];
  // 处理不同位的进制, 总位数达到设置的长度才开始升进制
  if (curVal.length === len) {
    let curValArr = curVal.split('');
    numList = curValArr.map((a) => {
      // 当前位本来就是36进制的
      return num10.indexOf(a) === -1 ? num36 : num10;
    });
    // 将36进制位的后一位到达9的10进制位变成36进制
    for (let i = 0; i < curValArr.length; i++) {
      if (numList[i].length === num36.length) continue;
      // 最高位达到9升36进制,非最高位达到9并且它的上一位到达36进制最后一个值也升36进制
      if (num10.indexOf(curValArr[i]) === num10.length - 1 && (i === 0 || curValArr[i - 1] === num36[num36.length - 1])) {
        numList[i] = num36;
      }
    }
  }
  let nextVal = plusOne(curVal, numList);
  // 超出最大值时报错
  if (nextVal.length > len) throw new Error('Digital exceeds the maximum');
  // 高位补0并返回
  return (new Array(len).join('0') + nextVal).substr(-1 * len);
}

// 计算指定位数可生成的最大编码量
function allCount(len) {
  let max = 0;
  // 计算超过10进制最大值后的数量
  for (let i = 0; i < len; i++) {
    let tmp = 26;
    for (let j = 0; j < len - i - 1; j++) {
      tmp = tmp * 10;
    }
    max += tmp;
  }
  // 10进制最大值
  max += Math.pow(10, len);
  console.log(max);
}

allCount(3);

// 测试
let testNum = '0';
for (let i = 0; i < 20000; i++) {
  testNum = nextVal(testNum, 3);
  console.log(testNum);
}

 

* 直接使用nodejs跑这段代码即可看到输出结果

【代码解析】

代码中共出现3个方法,生成编码主要使用了其中两个方法:plusOnenextVal,计算指定长度最大生成编码数量方法:allCount

plusOne 负责通过指定当前值和进制方案增加自然数1返回结果

nextVal 负责指定当前值和编码长度(数字位数)生成进制方案并调用plusOne获得结果并对结果进行范围判断(超过指定位数允许的最大值时将throw异常)、高位补0操作

allCount 传递编码长度计算可生成的最大编码数量,以便根据业务设定规则

 

posted @ 2021-05-14 11:45  yzeng  阅读(666)  评论(0编辑  收藏  举报