对有规则的礼券数字编码进行打乱和还原

起因

公司项目需要做几套编码,礼券码、接待码、兑换码等等,但是录入码的入口希望只有一个。这就需要编码上本身就要保存,可以用于识别功能的固定码。

原来一个12位随机码,现在要使用两位来标识功能。例如,11代表礼券12代表接待,那么编码上就会展现一定的规律。无论把标识码放在第几位使用几次都是比较容易识别的。

在网上找了一下也没有发现合适的方法来解决此问题,加密算法一般都是带字母的,我们必须要纯数字的。

还有就是可以使用密言来解决,增加另一个12位随机数作为密言,然后两个12位数进行异或操作可以解决此问题。但是因为一些遗留问题我们并不希望在数据库中增加额外的密言字段。

 

解决

最后我想到了一个办法,既不用密言,又可以让原来有规律的编码看上去规律没那么明显。

此方法不是加密算法所以肯定不能达到加密的效果,我暂且叫做把数字串打乱的方法。

其实道理很简单,把十进制数字转换成二进制数字,然后在二进制数固定的位数上增加0或1。还原的时候去掉固定位值上的数字即可。根据个人需要插入在第几位,插入几个值都是可以自由调整的。

这里需要注意无论是十进制数字还是二进制数字,都要想办法避免第一位是0,否则转换准确率将受到挑战。我的办法是将标识码第一位放在编码首位,并且不允许首位这个码为0。

我自己的代码做了几次一百万次的试验,还没有发现转换误差。

 

代码

package com.plsoft.pmall.utils;

import java.util.Random;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 生成二维码使用的编码
 * 如:消费者名片 - 10、活动礼券码 - 11、接待码 - 12、商品兑换码 - 13
 */
public class QRcodeNumber {

    /**
     * 传入功能标识获得编码
     * @param flag 标识 必须是两位数 并且第一位不能是0
     * @return 入参是null返回null 位数不对返回null 不是数字返回null 第一位是0返回null
     */
    public String getCode(String flag){
        //入参是null返回null
        if(flag == null || flag.equals("")){
            return null;
        }
        //位数不对返回null
        if(flag.length() != 2){
            return null;
        }
        //不是数字返回null
        Pattern pattern = Pattern.compile("[0-9]*");
        Matcher isNum = pattern.matcher(flag);
        if( !isNum.matches() ){
            return null;
        }
        //第一位是0返回null
        if(flag.substring(0,1).equals(0)){
            return null;
        }
        //编码规则:标识第一位 + 10位随机数 + 标识第二位
        String random_number = String.format("%010d", Math.abs(new Random().nextLong()) % 10000000000L);//10位随机数;
        String code = flag.substring(0,1) + random_number +flag.substring(1);
        return code;
    }

    /**
     * 获取功能标识码
     * @param code 编码
     * @return 位数不对返回null 不是数字返回null
     */
    public String getFlag(String code){
        //入参是null返回null
        if(code == null || code.equals("")){
            return null;
        }
        //位数不对返回null
        if(code.length() != 12){
            return null;
        }
        //不是数字返回null
        Pattern pattern = Pattern.compile("[0-9]*");
        Matcher isNum = pattern.matcher(code);
        if( !isNum.matches() ){
            return null;
        }
        //编码的第一位和最后一位
        String flag = code.substring(0,1) + code.substring(code.length()-1);
        return flag;
    }

    /**
     * 打乱编码
     * @param code 正常编码
     * @return
     */
    public String codeDisorganize(String code){
        //入参是null返回null
        if(code == null || code.equals("")){
            return null;
        }
        //位数不对返回null
        if(code.length() != 12){
            return null;
        }
        //不是数字返回null
        Pattern pattern = Pattern.compile("[0-9]*");
        Matcher isNum = pattern.matcher(code);
        if( !isNum.matches() ){
            return null;
        }

        //转换成二进制并在第10位插入0,打乱编码
        String two = Long.toBinaryString(Long.valueOf(code));
        two = two.substring(0,10) + "0" + two.substring(10);
        String disorganizeCode = Long.valueOf(two,2).toString();
        return disorganizeCode;
    }

    /**
     * 恢复编码
     * @param disorganizeCode 打乱的编码
     * @return
     */
    public String codeRestore(String disorganizeCode){
        //入参是null返回null
        if(disorganizeCode == null || disorganizeCode.equals("")){
            return null;
        }
        //不是数字返回null
        Pattern pattern = Pattern.compile("[0-9]*");
        Matcher isNum = pattern.matcher(disorganizeCode);
        if( !isNum.matches() ){
            return null;
        }
        //转换成二进制去掉第十位数字
        String two = Long.toBinaryString(Long.valueOf(disorganizeCode));
        two = two.substring(0,10) + two.substring(10+1);
        String code = Long.valueOf(two,2).toString();
        return code;
    }

    /**
     * 生成并打乱编码
     * @param flag 标识
     * @return
     */
    public String getCodeDisorganize(String flag){
        String code = getCode(flag);
        String disorganizeCode = codeDisorganize(code);
        return disorganizeCode;
    }

    /**
     * 测试方法
     * @param args
     */
    public static void main(String[] args) {
        QRcodeNumber test = new QRcodeNumber();
        for(int l=0;l<1000000;l++){
            String code = test.getCode("12");
            String disorganizeCode = test.codeDisorganize(code);
            String code1 = test.codeRestore(disorganizeCode);
            String flag = test.getFlag(code1);

            System.out.print("编码:"+code+"   打乱编码:"+disorganizeCode+"   恢复编码:"+code1+"   功能标识:"+flag+"   是否准确还原:"+code.equals(code1));
            System.out.println("");
        }
    }

}

结果

只是一百万次的一部分

编码:190938747752   打乱编码:381796356968   恢复编码:190938747752   功能标识:12   是否准确还原:true
编码:198317140492   打乱编码:396422507020   恢复编码:198317140492   功能标识:12   是否准确还原:true
编码:192320558332   打乱编码:384520344828   恢复编码:192320558332   功能标识:12   是否准确还原:true
编码:125924331642   打乱编码:251820560506   恢复编码:125924331642   功能标识:12   是否准确还原:true
编码:189146322322   打乱编码:378124883346   恢复编码:189146322322   功能标识:12   是否准确还原:true
编码:131905761882   打乱编码:263707570778   恢复编码:131905761882   功能标识:12   是否准确还原:true
编码:121553498692   打乱编码:243020542532   恢复编码:121553498692   功能标识:12   是否准确还原:true
编码:106515401172   打乱编码:212950059476   恢复编码:106515401172   功能标识:12   是否准确还原:true
编码:188032064632   打乱编码:375936883832   恢复编码:188032064632   功能标识:12   是否准确还原:true
编码:126401147142   打乱编码:252700029190   恢复编码:126401147142   功能标识:12   是否准确还原:true
编码:198738210362   打乱编码:397380447802   恢复编码:198738210362   功能标识:12   是否准确还原:true
编码:140145652832   打乱编码:280268960864   恢复编码:140145652832   功能标识:12   是否准确还原:true
编码:176124884942   打乱编码:352218544078   恢复编码:176124884942   功能标识:12   是否准确还原:true
编码:133437939942   打乱编码:266850361574   恢复编码:133437939942   功能标识:12   是否准确还原:true
编码:182091456312   打乱编码:364090695480   恢复编码:182091456312   功能标识:12   是否准确还原:true
编码:150122544032   打乱编码:300177963936   恢复编码:150122544032   功能标识:12   是否准确还原:true
编码:122366359692   打乱编码:244638709900   恢复编码:122366359692   功能标识:12   是否准确还原:true
编码:132578551622   打乱编码:265051449158   恢复编码:132578551622   功能标识:12   是否准确还原:true
编码:125089602772   打乱编码:250046307540   恢复编码:125089602772   功能标识:12   是否准确还原:true
编码:157058911002   打乱编码:314093652762   恢复编码:157058911002   功能标识:12   是否准确还原:true
编码:121568404182   打乱编码:243035448022   恢复编码:121568404182   功能标识:12   是否准确还原:true
编码:169999958902   打乱编码:339919602550   恢复编码:169999958902   功能标识:12   是否准确还原:true
编码:138663454862   打乱编码:277176150158   恢复编码:138663454862   功能标识:12   是否准确还原:true
编码:115203985932   打乱编码:230362796556   恢复编码:115203985932   功能标识:12   是否准确还原:true

 

转载于:https://my.oschina.net/u/3452433/blog/1002608

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值