zoukankan      html  css  js  c++  java
  • 参考护照编码实现算法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 传递编码长度计算可生成的最大编码数量,以便根据业务设定规则

    致读者:感谢你阅读本文,请随手点击右下角的推荐或分享,谢谢!
  • 相关阅读:
    Java静态方法 与 非静态方法(实例方法)的区别
    java实现多态 方法的重写和重载的区别
    Linxu系统dpkg命令
    2016/5/23 阴天
    C#网络应用编程 类,构造函数,方法,属性和字段
    网络应用编程中的 ref
    编程经验(C#)
    Unity常用API备忘录
    Unity快捷键总结
    Unity ScriptObject创建Asset文件
  • 原文地址:https://www.cnblogs.com/yzeng/p/14767961.html
Copyright © 2011-2022 走看看