java获取A00001、A00002...AA0001...到ZZZZZZ的流水号算法(字母加数字)

需求

流水号生成的一种算法。

需求:生成指定位数的流水号,如:生成6位流水号,从A00001、A00002一直递增到ZZZZZZ结束。

000000 -> 999999

A00000 -> A99999

B00000 -> B99999 

 ……          

Z00000 -> Z99999

ZA0000 -> ZA9999 ->ZZZZZZ

算法介绍

  1. 定义一个可选字母的数组A-Z;
    private static final Character[] CHARS = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
                'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'
        };

    在这里可以去掉一些和数字长相冲突的字母,比如O.

  2. 定义静态代码块,计算出A00000 . AA0000、AAA000、AAAA00、AAAAA0、AAAAAA的数字;

    private static final int CHAR_LEN;
    private static final String MAX;
    private static final Long[] BOUNDARIES;
    
     static {
            CHAR_LEN = CHARS.length;
    
            Character lastChar = CHARS[CHAR_LEN - 1];
    
            MAX = StringUtils.leftPad(String.valueOf(lastChar), DEFALUT_LEN, lastChar);
    
            BOUNDARIES = new Long[DEFALUT_LEN + 2];
    
            Long last = 0L;
    
            BOUNDARIES[0] = 0L;
    
            for (int i = 1; i <= DEFALUT_LEN + 1; i++) {
                int t = i - 1;
                BOUNDARIES[i] = last + (long) Math.pow(10, DEFALUT_LEN - t) * (long) Math.pow(CHAR_LEN, (i - 1));
    
                last = BOUNDARIES[i];
            }
            log.info("code generator boundaries: " + Arrays.toString(BOUNDARIES));
        }
    
  3. 如果目标数字大于等于BOUNDARIES的最后一位,也就是超出了我们定义的最大长度。抛出异常;

    if (num >= BOUNDARIES[DEFALUT_LEN + 1]) {
         throw new RuntimeException("the code is has reached it's maximum value [" + MAX + "]");
            }

  4. 获取目标数字是在000000、A00000 、AA0000、AAA000、AAAA00、AAAAA0、AAAAAA这些区间的哪一段。

    int initialIndex = Arrays.binarySearch(BOUNDARIES, num);
  5. 计算出所在区间的步长(从一个字母到下一个字母所经过的数字,如A00000到AA0000中的步长 ,也就是A00000到B00000 的步长就是(3600000-1000000)/26 这里26是上面定义的字母数组的长度 ),然后开始循环,从一步获取的索引位置开始,到BOUNDARIES数组结束;

  6. 在循环中重新计算出目标数字所在的区间及步长。

完整代码

import lombok.extern.java.Log;
import org.apache.commons.lang3.StringUtils;

import java.util.Arrays;

/**
 * @Author: Eynait
 * @Date: 2023/7/28 16:18
 */
@Log
public class Coder {

    private static final int DEFALUT_LEN = 6;

    private static final Character[] CHARS = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
            'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'
    };
    private static final int CHAR_LEN;
    private static final String MAX;
    private static final Long[] BOUNDARIES;

    static {
        CHAR_LEN = CHARS.length;

        Character lastChar = CHARS[CHAR_LEN - 1];

        MAX = StringUtils.leftPad(String.valueOf(lastChar), DEFALUT_LEN, lastChar);

        BOUNDARIES = new Long[DEFALUT_LEN + 2];

        Long last = 0L;

        BOUNDARIES[0] = 0L;

        for (int i = 1; i <= DEFALUT_LEN + 1; i++) {
            int t = i - 1;
            BOUNDARIES[i] = last + (long) Math.pow(10, DEFALUT_LEN - t) * (long) Math.pow(CHAR_LEN, (i - 1));

            last = BOUNDARIES[i];
        }
        log.info("code generator boundaries: " + Arrays.toString(BOUNDARIES));
    }



    public static String generator(long num) {
        if (num >= BOUNDARIES[DEFALUT_LEN + 1]) {
            throw new RuntimeException("the code is has reached it's maximum value [" + MAX + "]");
        }

        int initialIndex = Arrays.binarySearch(BOUNDARIES, num);

        if (initialIndex < 0) {
            initialIndex = -(initialIndex + 2);
        }

        if (initialIndex == 0) {
            return StringUtils.leftPad(String.valueOf(num), DEFALUT_LEN, "0");
        }

        StringBuffer result = new StringBuffer();

        Long boundary = BOUNDARIES[initialIndex];
        long step = (BOUNDARIES[initialIndex + 1] - boundary) / CHAR_LEN;

        for (int i = initialIndex; i > 0; i--) {
            if (boundary < CHAR_LEN) {
                result.append(num);
                break;
            }
            long diff = num - boundary;

            long targetIndex = diff / step;

            result.append(CHARS[(int) targetIndex]);
            boundary = boundary + step * targetIndex;
            step = step / CHAR_LEN;
        }
        if (initialIndex < DEFALUT_LEN) {
            result.append(StringUtils.leftPad(String.valueOf(num - boundary), DEFALUT_LEN - initialIndex, "0"));
        }
        return result.toString();
    }


    public static void main(String[] args) {

        for (int i = 999999; i < 9999999; i++) {
            System.out.println(i + " - " + generator(i));
        }

    }

}

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值