生成类似excel横坐标的字母序列(算法)

前言

做业务有时候需要导出excel,还得动态设置样式,代码循环的时候只知道当前列的数字位置,不知道excel中表示的字母编号,需要动态的算出表格横坐标的字母编号,下面给出可以直接拿去使用的代码以及生成过程的说明。

序列号(数字)生成字母序列

类似excel表格

ABAAABABC
1
2

我们的需求:传入一个序列号(数字),表示横坐标的数字形式,从0开始,例如 0 则表示 A,1 则表示 B,25 表示 Z,26 表示 AA,… 以此类推,702 表示 AAA,730 表示 ABC

我们先给字母 A 到 Z 定个编号,从 0 到 25

寻找规律

0-25 表示 A-Z             字母序列 = ([字母编号]) 
26-701 表示 AA-ZZ         字母序列 = ( [(floor(序列号/26)-1) % 26] | [序列号%26] ) 
702-18277 表示 AAA-ZZZ    字母序列 = ( [(floor((floor(序列号/26)-1)/26)-1) % 26] | [(floor(序列号/26)-1) % 26] | [序列号%26] ) 

输入 730 ,得到 ABC

我们给输出的字符串从右到左的每个字符位置编号

字符ABC
位置210

可以看出,当输出只有一个字母的时候,序列号=字母编号

当输出多个字母的时候,

0 号位置的 字母编号 = 730 % 26,

1 号位置的 字母编号 = (floor(730 / 26) - 1) % 26,

2 号位置的 字母编号 = (floor(floor(730 / 26) - 1) / 26 - 1) % 26

从 0 号位置到 2 号位置,每次多除了一次26

直观一点的计算过程如下

0号位:730 / 26 = 282 --- C
1号位:(28 - 1) / 26 = 11 --- B
2号位:(1 - 1) /26 = 00 --- A

所以字符串的每个字母就是余数对应的字符

java代码如下:

    /**
     * 生成字母序列号,类似excel表格的列名(A、B、C、...AA、AB、AC...)
     *
     * @param serialNum 序列号,从0开始;0 -> a,25 -> z,26 -> aa,702 -> aaa, 730 -> abc
     * @param upper     是否输出大写
     * @return 结果
     */
    public static String genLetterSerial(int serialNum, boolean upper) {
        if (serialNum < 0) {
            return "";
        }
        StringBuilder sb = new StringBuilder();
        // Ascii,A:65,a:97
        int letterA = upper ? 65 : 97;
        int chunkCount = (int) Math.floor(serialNum / 26.0);
        int pos = serialNum % 26;

        do {
            char c = (char) (letterA + pos);
            sb.append(c);
            if (chunkCount < 1) {
                break;
            }

            int chunkNum = chunkCount - 1;
            pos = chunkNum % 26;
            chunkCount = (int) Math.floor(chunkNum / 26.0);
        } while (true);

        return sb.reverse().toString();
    }

逆向(字母序列反向算出序列号,如 ABC -> 730)

从字母序列逆向算出序列号的过程也很简单

还是用 730 -> ABC 的例子

0号位:730 / 26 = 282
1号位:(28 - 1) / 26 = 11
2号位:(1 - 1) /26 = 00

定义一条公式 (x - 1) / 26 = z 余 y

可以看得出来,我们只需要知道 0 号位置的计算结果以及余数就可以得到最终的 序列号 = 28 * 26 + 2 = 730

(x - 1) / 26 = z 余 y 套到上面的过程中,可以发现,其实 2 号位置的 x 是 1 号位置的 z ,1 号位置的 x 是 0 号位置的 z

x=z*26 + y + 1

这不就简单了吗,我们只要从2号位置开始一步一步算出 0 号位置的 z 和 y,就能得到最终的序列号

逆向开始时,我们只能确定每个位置的余数是什么(根据每个位置的字母可以确定),以及最后一位(2号位)的被除数一定是(1 - 1),商一定是 0

我们从 2 号位开始算

2号位:y=0, z=0, x=1
1号位:y=1, z=2号位x = 1, x=1*26 + 1 + 1 = 28
0号位:y=2, z=1号位x = 28, x=28*26 + 1 + 1 = 732

最终序列号:z * 26 + y = 28 * 26 + 2 = 730

java代码如下:

    /**
     * genLetterSerial的逆过程,根据字母序列,逆向出序列号
     *
     * @param letterSerial 字母序列字符串,如 a -> 0, abc -> 730
     * @return 结果
     */
    public static int letterSerialToSerialNum(String letterSerial) {
        if (Objects.equals(letterSerial, "")) {
            return -1;
        }
        // 全部字母转小写
        letterSerial = letterSerial.toLowerCase();
        char[] charArray = letterSerial.toCharArray();

        int z = 0;
        int y = charArray[0] - 97;

        for (int i = 1; i < charArray.length; i++) {
            z = z * 26 + y + 1;
            y = charArray[i] - 97;
        }

        return z * 26 + y;
    }
  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值