coax

导航

编码生成 进位简洁版 AAAA-01->ZZZZ-99

背景:

    需求要生成满足AAAA-01,AAAA-02....AAAA-99....ZZZZ-99格式的编码。

tip:

   有现成的可用CV,但是这两天比较闲。自己手撸,当前进位存储地方不在考虑范围,存redis,mem-cache,db,内存随意。只考虑进位

   简单描述:分三部分1.前缀类 2.后缀类 3.进位工具

1.前缀类

package com.coax.demo.handler.systemcode.model;

import com.coax.demo.handler.systemcode.tool.CodePrefixTool;
import lombok.AccessLevel;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import lombok.experimental.FieldDefaults;

/**
 * 编码前4位自增 AAAA->AAAB->....->ZZZZ
 *
 * @author <a href="tomail:coax@outlook.it">chengxiaohong<a/>
 * @version v1.5
 * @since 2020/7/27
 */
@Data
@Accessors(chain = true)
@FieldDefaults(level = AccessLevel.PRIVATE)
@NoArgsConstructor
public class CodePrefix implements SystemCode {

    /**
     * 自增区间
     */
    String current;

    public CodePrefix(String current) {
        this.current = current;
    }

    /**
     * 获取下一个code CodePrefix
     *
     * @return String
     */
    @Override
    public String next() {
        return CodePrefixTool.up(this.current);
    }
}

2.后缀类

 

package com.coax.demo.handler.systemcode.model;

import lombok.AccessLevel;
import lombok.Data;
import lombok.experimental.Accessors;
import lombok.experimental.FieldDefaults;
import org.apache.commons.lang3.StringUtils;

/**
 * * 编码后2位循环 01->99->01->99
 *
 * @author <a href="tomail:coax@outlook.it">chengxiaohong<a/>
 * @version v1.5
 * @since 2020/7/27
 */
@Data
@Accessors(chain = true)
@FieldDefaults(level = AccessLevel.PRIVATE)
public class CodeSuffix implements SystemCode {

    private CodeSuffix() {
    }

    /**
     * 循环开区间
     */
    private static int PART_START = 0, PART_END = 99;
    /**
     * 编码后区间
     */
    int current;

    public CodeSuffix(int current) {
        this.current = current;
    }

    /**
     * 获取下一位后编码
     *
     * @return 下一位后编码
     */
    public String next() {
        int r = current;
        if (PART_END <= this.current || PART_START >= this.current) {
            r = PART_START;
        }
        return StringUtils.leftPad(String.valueOf(r + 1), 2, String.valueOf(0));
    }

    /**
     * 前缀是否需要进位 和 后缀是否重置 :条件(到达最大值)
     *
     * @param suffix 后缀值
     * @return boolean
     */
    public static boolean resetCheck(int suffix) {
        return suffix == PART_END;
    }
}

3. 进位工具类

package com.coax.demo.handler.systemcode.tool;

import org.apache.commons.lang3.StringUtils;

import java.util.Arrays;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

/**
 * 前缀映射类
 *
 * @author <a href="tomail:coax@outlook.it">chengxiaohong<a/>
 * @version v1.5
 * @since 2020/7/27
 */
public class CodePrefixTool {

    private CodePrefixTool() {
    }

    /**
     * 自增数据数组源
     */
    private static final char[] PREFIX_SOURCES_ARRAY = {
            '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 String PREFIX_SOURCES = String.copyValueOf(PREFIX_SOURCES_ARRAY);

    private static final int END_MAX = 25;

    private static final int SIZE = 4;

    /**
     * 自增开区间
     */
    private static final int[] START = {0, 0, 0, 0};

    /**
     * 自增闭区间
     */
    private static final int[] END = {END_MAX, END_MAX, END_MAX, END_MAX};

    /**
     * 向上偏移一位 AAAA->AAAB
     *
     * @return String
     */
    public static String up(String current) {
        final int[] desc = checkAndGet(current);
        return IntStream.rangeClosed(0, desc.length - 1).mapToObj(i -> {
            return String.valueOf(PREFIX_SOURCES_ARRAY[desc[i]]);
        }).collect(Collectors.joining());
    }

    /**
     * 向下偏移一位 AAAB->AAAA
     *
     * @return String
     */
    public static String down(String sources) {
        //FIXME:程小洪 2020/7/27 未实现
        return null;
    }

    private static int[] checkAndGet(String sources) {
        //初始化
        if (StringUtils.isBlank(sources)) {
            return START;
        }

        //长度校验
        if (sources.length() != START.length) {
            throw new IllegalArgumentException(
                    String.format("源数据长度不满足,目标长度:%d,结果长度:%d", START.length, sources.length())
            );
        }

        //可用性校验 大小写兼容
        char[] sourcesArray = sources.toUpperCase().toCharArray();
        for (char c : sourcesArray) {
            if (PREFIX_SOURCES.indexOf(c) == -1) {
                throw new IllegalArgumentException("源数据应只能是大写字母");
            }
        }

        int[] ret = new int[SIZE];
        for (int i = 0; i < sourcesArray.length; i++) {
            char c = sourcesArray[i];
            ret[i] = PREFIX_SOURCES.indexOf(c);
        }

        if (Arrays.equals(ret, END)) {
            throw new IllegalArgumentException("此规则已达到最大取值范围");
        }


        return exePlus(ret, ret.length - 1, false);
    }

    /**
     * 向上偏移一位
     *
     * @param sources    源数据
     * @param currentCyc 当次递归入栈次数(sources 长度向下递减取反)
     * @param frontBiz   上次是否增加
     * @return int[]
     */
    private static int[] exePlus(int[] sources,
                                 int currentCyc,
                                 boolean frontBiz) {
        //是否需要偏移
        sources[currentCyc] = sources[currentCyc] + (frontBiz ? 0 : 1);
        //偏移进位
        if (sources[currentCyc] == PREFIX_SOURCES_ARRAY.length) {
            sources[currentCyc] = 0;
            sources[currentCyc - 1] = sources[currentCyc - 1] + 1;
            //偏移进位溢出
            if (sources[currentCyc - 1] == PREFIX_SOURCES_ARRAY.length) {
                exePlus(sources, currentCyc - 1, true);
            }
        } else {
            return sources;
        }
        return sources;
    }
}

4.前缀以及编码接口 其实没有必要。只有一个接口方法

package com.coax.demo.handler.systemcode.model;


/**
 * @author <a href="tomail:coax@outlook.it">chengxiaohong<a/>
 * @version v1.5
 * @since 2020/7/27
 */
public interface SystemCode {

    /**
     * 获取下一个code
     *
     * @return String
     */
    String next();
}

跑一下测试:

package com.coax.demo;

import com.coax.demo.systemcode.model.CodeSuffix;
import com.coax.demo.systemcode.tool.CodePrefixTool;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.runners.MockitoJUnitRunner;

/**
 * 系统编码生成组件测试
 *
 * @author <a href="tomail:coax@outlook.it">chengxiaohong<a/>
 * @version v1.5
 * @since 2020/7/27
 */
@RunWith(MockitoJUnitRunner.class)
public class GoodsSystemCodeHandler {

    /**
     * 空值  初始化测试
     */
    @Test
    public void codePrefixTool1() {
        CodePrefixTool.up(null);
    }

    /**
     * 入参长度不足测试
     */
    @Test(expected = IllegalArgumentException.class)
    public void codePrefixTool2() {
        CodePrefixTool.up("AAA");

    }

    /**
     * 非法入参测试
     */
    @Test(expected = IllegalArgumentException.class)
    public void codePrefixTool3() {
        CodePrefixTool.up("aaa");
    }

    /**
     * 最大取值范围测试
     */
    @Test(expected = IllegalArgumentException.class)
    public void codePrefixTool4() {
        CodePrefixTool.up("ZZZZ");
    }

    /**
     * 正常取值
     */
    @Test()
    public void codePrefixTool5() {
        System.out.println(CodePrefixTool.up("AAAA"));
    }


    /**
     * 跨界取值
     */
    @Test()
    public void codePrefixTool6() {
        System.out.println(CodePrefixTool.up("AAZZ"));
    }

    /**
     * 自增后缀测试
     */
    @Test
    public void CodeSuffix1() {
        CodeSuffix codeSuffix = new CodeSuffix(0);
        System.out.println(codeSuffix.next());
        codeSuffix = new CodeSuffix(100);
        System.out.println(codeSuffix.next());
        codeSuffix = new CodeSuffix(99);
        System.out.println(codeSuffix.next());
        codeSuffix = new CodeSuffix(10);
        System.out.println(codeSuffix.next());
    }


}

emmm:虽然烂得一匹。勉强交差,可以回家打游戏去了 。还有 满99进位就不贴了。写得太丑

 

posted on 2020-07-29 15:34  coax  阅读(771)  评论(0编辑  收藏  举报