自定义62进制实现字符串自增,表示238328个数字只需3个字符

【看代码直接跳到最后】

一.需求【数据库不支持字符串自增,需要自己实现】

        1.当需要生成一些唯一编号的数据时,通常都是使用uuid作为唯一值,但当编号有上下级,如行政区划码,物品分类树,多级目录分类

        2.我们只拿到某一给节点时,需要快速解析出该节点的所有父级数据,以及子集数据聚合时,就需要用到一个在该节点唯一的编码,

        3.如已知区划码【510107】,我们可一下子道这个区划码对应的是【51:四川,01:成都,07:武侯区】,要查询【510107】下面的数据,只需要在sql中 加一个【code like '510107%'】条件即可

        我们在添加这种多层级,由要求能快速统计分析的数据时就需要为每一条数据生成唯一的code,并且通过这个code可直观的看出层级关系,要保证唯一并使code精简只能通过code的自增才能同时满足这两个条件

二.常见方案

  1. 通过数字解析实现code自增;
    1. 局限性:
      1. 需要的字符太长时解析为数字任意超出长度限制
      2. 只支持数字操作,当需要加入大小写字母时则不支持
  2. 直接使用uuid;
    1. 局限性:
      1. 每一级的code都太长,不够精简
      2. 当层级太多时,子级的code长度将难以接受
  3. 使用随机字符;【最容易实现,但一定会重复】

三.解决办法

        通过自定义字符串自增实现code的生成;

        如下为两个数字相加的代码:

    private static String numberAdd(String d1, String d2) {
        int l1 = d1.length() - 1, l2 = d2.length() - 1;
        int t = 0;//用于记录是否进位的变量
        StringBuilder s = new StringBuilder();
        while (l1 >= 0 || l2 >= 0 || t > 0) {//当d1或d2没有遍历完,或者有需要进位的数字,则进行循环
            if (l1 >= 0) t += d1.charAt(l1--) - '0';//t=t+d1的当前位数字
            if (l2 >= 0) t += d2.charAt(l2--) - '0';//t=t+d2的当前位数字
            s.append(t % 10);//取出t的个位加到字符串上面,最早得到如81,891,8991
            t /= 10;//t舍去个位的数字
        }
        return s.reverse().toString();//将s反转即可得到两个数相加后的数字
    }

        基于上述字符相加的基本规则,很容易得到大写字母相加,小写字母相加,数字/大写字母/小写字母组合相加的代码

        有了字符串相加的代码,自增将是+1操作,很容易实现【具体代码不再赘述,文章最后粘贴有】

四.测试效果

    @Test
    public void test1() {
        System.out.println(numberAdd("9", "9"));//18
        System.out.println(numberAdd("99", "99"));//198
        System.out.println(numberAdd("9999", "9999"));//19998
        System.out.println(numberAdd("99999999", "99999999"));//199999998
        System.out.println(numberAdd("9999999999999999", "9999999999999999"));//19999999999999998
        System.out.println(numberAdd("99999999999999999999999999999999", "99999999999999999999999999999999"));//199999999999999999999999999999998
        System.out.println(numberAdd("9999999999999999999999999999999999999999999999999999999999999999", "9999999999999999999999999999999999999999999999999999999999999999"));//19999999999999999999999999999999999999999999999999999999999999998
        System.out.println(numberAdd("99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999", "99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999"));//199999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999998
        System.out.println(numberAdd("9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999", "9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999"));//19999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999998
        System.out.println(numberAdd("99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999", "99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999"));//199999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999998
    }

五.源代码【数字,大写字母,小写字母,数字/大小写字母组合自增的代码】

注意,下面代码中使用了hutool的字符串工具,可替换为其他字符串工具

package com.wanger.utils.str;

import cn.hutool.core.util.StrUtil;

/**
 * @Author: wanger
 * @Date: 2023/10/24 16:32
 * @Description: 字符串相加与自增工具,支持数字相加,大写字母相加,小写字母相加,数字大小写字母相加,以及对应的自增操作
 */
public class CodeUtils {
    /**
     * 通用单一字符串相加,如大写字母,小写字母,数字等
     *
     * @param d1       字符串1
     * @param d2       字符串2
     * @param start    起始字符,如数据的为0
     * @param stepSize 涉及到的步长,如数字的为10
     * @return 返回相加后的字符串
     */
    private static String characterAddition(String d1, String d2, char start, int stepSize) {
        int i = d1.length() - 1, j = d2.length() - 1, d = 0;
        StringBuilder s = new StringBuilder();
        while (i >= 0 || j >= 0 || d > 0) {
            if (i >= 0) d += d1.charAt(i--) - start;
            if (j >= 0) d += d2.charAt(j--) - start;
            s.append((char) (d % stepSize + start));
            d /= stepSize;
        }
        return s.reverse().toString();
    }

    /**
     * 数字相加操作
     *
     * @param d1 数字1
     * @param d2 数字2
     * @return 返回相加后的数字
     */
    public static String digitAddition(String d1, String d2) {
        if (StrUtil.isNumeric(d1) && StrUtil.isNumeric(d2)) {
            return characterAddition(d1, d2, '0', 10);
        } else throw new RuntimeException("数字相加的字符串内容只能是数字d1=" + d1 + ",d2=" + d2);
    }

    /**
     * 大写字母相加,注意A对应十进制的0所以A+A=A
     *
     * @param d1 大写字母1
     * @param d2 大写字母2
     * @return 相加后的大写字母
     */
    public static String upperCaseAddition(String d1, String d2) {
        if (StrUtil.isUpperCase(d1) && StrUtil.isUpperCase(d2)) {
            return characterAddition(d1, d2, 'A', 26);
        } else throw new RuntimeException("大写字母相加的字符串内容只能是大写字母d1=" + d1 + ",d2=" + d2);
    }

    /**
     * 小写字母相加,注意a对应十进制的0所以a+a=a
     *
     * @param d1 小写字母1
     * @param d2 小写字母2
     * @return 相加后的小写字母
     */
    public static String lowerCaseAddition(String d1, String d2) {
        if (StrUtil.isLowerCase(d1) && StrUtil.isLowerCase(d2)) {
            return characterAddition(d1, d2, 'a', 26);
        } else throw new RuntimeException("小写字母相加的字符串内容只能是小写字母d1=" + d1 + ",d2=" + d2);
    }

    /**
     * 数字自增
     *
     * @param digit       要自增的数字
     * @param limitLength 长度限制
     * @return 返回自增后的数字
     */
    public static String digitalIncrement(String digit, int limitLength) {
        return keepSpecifiedLength(digitAddition(digit, "1"), '0', limitLength);
    }

    /**
     * 数字自增
     *
     * @param digit 要自增的数字
     * @return 返回自增后的数字
     */
    public static String digitalIncrement(String digit) {
        return digitalIncrement(digit, -1);
    }

    /**
     * 大写字母自增
     *
     * @param digit       要自增的大写字母
     * @param limitLength 长度限制
     * @return 返回自增后的大写字母
     */
    public static String upperCaseIncrement(String digit, int limitLength) {
        return keepSpecifiedLength(upperCaseAddition(digit, "B"), 'A', limitLength);
    }

    /**
     * 大写字母自增
     *
     * @param digit 要自增的大写字母
     * @return 返回自增后的大写字母
     */
    public static String upperCaseIncrement(String digit) {
        return upperCaseIncrement(digit, -1);
    }

    /**
     * 小写字母自增
     *
     * @param digit       要自增的小写字母
     * @param limitLength 长度限制
     * @return 返回自增后的小写字母
     */
    public static String lowerCaseIncrement(String digit, int limitLength) {
        return keepSpecifiedLength(lowerCaseAddition(digit, "b"), 'a', limitLength);
    }

    /**
     * 小写字母自增
     *
     * @param digit 要自增的小写字母
     * @return 返回自增后的小写字母
     */
    public static String lowerCaseIncrement(String digit) {
        return lowerCaseIncrement(digit, -1);
    }

    /**
     * 数字,大写字母,小写字母组合相加,如9+1=A,Z+1=a,z+1=10
     *
     * @param d1 字符串1
     * @param d2 字符串2
     * @return 返回相加后的字符串
     */
    public static String characterAddition(String d1, String d2) {
        if (d1 == null) d1 = "";
        if (d2 == null) d2 = "";
        numericUpperAndLowerCaseLetterDetermination(d1);
        numericUpperAndLowerCaseLetterDetermination(d2);
        int i = d1.length() - 1, j = d2.length() - 1, d = 0;
        StringBuilder s = new StringBuilder();
        while (i >= 0 || j >= 0 || d > 0) {
            if (i >= 0) d += characterDifference(d1.charAt(i--));
            if (j >= 0) d += characterDifference(d2.charAt(j--));
            s.append(characterRestore(d));
            d /= 62;
        }
        return s.reverse().toString();
    }

    /**
     * 对字符串进行前缀补0或删除前缀实现使其保持指定的长度
     *
     * @param str             要进行规整的字符串
     * @param prefixCharacter 要补充的前缀字符
     * @param limitLength     指定的长度,-1表示不进行长度限制
     * @return 返回规整后的字符串
     */
    private static String keepSpecifiedLength(String str, char prefixCharacter, int limitLength) {
        StringBuilder s = new StringBuilder(new StringBuilder(str).reverse());
        if (limitLength > 0) {
            int l = s.length();
            if (l > limitLength) s.delete(limitLength, l);
            else while (limitLength-- > l) s.append(prefixCharacter);
        }
        return s.reverse().toString();
    }

    /**
     * 判断是否为数字或者大小写字母
     *
     * @param d 要判断的字符串
     */
    private static void numericUpperAndLowerCaseLetterDetermination(String d) {
        RuntimeException ex = new RuntimeException("相加的字符串内容只能为数字或者大小写字母:" + d);
        if (d == null) throw ex;
        for (char c : d.toCharArray()) {
            if (c < '0' || (c > '9' && c < 'A') || (c > 'Z' && c < 'a') || c > 'z') {
                throw ex;
            }
        }
    }

    /**
     * 获取差值
     *
     * @param c 要获取差值的字符
     * @return 返回差值
     */
    private static int characterDifference(char c) {
        if (Character.isDigit(c)) {
            return c - '0';
        } else if (Character.isUpperCase(c)) {
            return c - 'A' + 10;
        } else {
            return c - 'a' + 36;
        }
    }

    /**
     * 又差值还原到字符
     *
     * @param d 差值
     * @return 还原后的字符
     */
    private static char characterRestore(int d) {
        int i = d % 62;
        if (i < 10) {
            return (char) (i + '0');
        } else if (i < 36) {
            return (char) (i + 'A' - 10);
        } else {
            return (char) (i + 'a' - 36);
        }
    }


    /**
     * code自增
     * 使用的字符序【0~9A~Za~z】共62个字符,3个字符可计数62*62*62位
     *
     * @param code        要自增的code
     * @param limitLength 长度限制
     * @return 返回自增后的code
     */
    public static String codeIncrement(String code, int limitLength) {
        if (code == null) code = "";
        return keepSpecifiedLength(characterAddition(code, "1"), '0', limitLength);
    }

    /**
     * 字符自增
     *
     * @param code 要自增的字符
     * @return 返回自增后的字符
     */
    private static String codeIncrement(String code) {
        return codeIncrement(code, -1);
    }

    /**
     * 获取编码,并加lastCode自增
     *
     * @param parentCode 父级code
     * @param lastCode   子级最后一个code
     * @return 返回一个子级自增后的编码
     */
    public static String getCode(String parentCode, String lastCode) {
        return getCode(parentCode, lastCode, -1);
    }

    /**
     * 获取编码,并加lastCode自增
     *
     * @param parentCode  父级code
     * @param lastCode    子级最后一个code
     * @param limitLength lastCode自增后的字符串长度
     * @return 返回一个父级code+子级自增后的code字符串
     */
    public static String getCode(String parentCode, String lastCode, int limitLength) {
        if (lastCode == null) lastCode = "";
        if (parentCode == null) {
            return codeIncrement(lastCode, limitLength);
        } else {
            return parentCode + codeIncrement(lastCode.replaceFirst(parentCode, lastCode), limitLength);
        }
    }

    public static void main(String[] args) {
        String digit = "0";
        String upperCase = "A";
        String lowerCase = "a";
        String code = "0";
        for (int i = 0; i < 1000000; i++) {
            System.out.println("数字自增【" + digit + "】\t,大写字母自增【" + upperCase + "】\t,小写字母自增【" + lowerCase + "】\t,组合自增【" + code + "】\t");
            digit = digitalIncrement(digit);
            upperCase = upperCaseIncrement(upperCase);
            lowerCase = lowerCaseIncrement(lowerCase);
            code = codeIncrement(code);
        }
        System.out.println(characterAddition("123", "123"));
        System.out.println(digitAddition("9999", "9999"));
        System.out.println(upperCaseAddition("ZZZ", "AZZ"));
        System.out.println(upperCaseAddition("A", "B"));
        System.out.println(lowerCaseAddition("zaz", "aza"));
        System.out.println(digitalIncrement("999", 5));
        System.out.println(digitalIncrement("999", 1));
        System.out.println(digitalIncrement("999", 0));
        System.out.println(digitalIncrement("999"));
        System.out.println(upperCaseIncrement("ZZZ", 5));
        System.out.println(upperCaseIncrement("ZZZ", 1));
        System.out.println(upperCaseIncrement("ZZZ", 0));
        System.out.println(upperCaseIncrement("ZZZ"));
        System.out.println(lowerCaseIncrement("zzz", 5));
        System.out.println(lowerCaseIncrement("zzz", 1));
        System.out.println(lowerCaseIncrement("zzz", 0));
        System.out.println(lowerCaseIncrement("zzz"));
        System.out.println(getCode(null, "zzz", 10));
        System.out.println(getCode(null, "zzz"));
        System.out.println(codeIncrement("zzz"));
        System.out.println(codeIncrement("9"));
        System.out.println(codeIncrement("Z"));
        System.out.println(codeIncrement("z"));
    }

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值