十进制与26进制英文字母互转

最近在封装Excel组件,需要提供两个接口,分别根据单元索引和单元名称访问单元格。例如,GetCell(1, 2)和GetCell(“A2”),这两种方法返回的结果是相同的。这里遇到一个问题,如何在单元索引([1,2])和单元名称(A2)之间相互转换?
由于在单元索引和单元名称中,行号是相同的,所以我们只需要转换列号就可以了。本来以为是个很简单的问题,结果调试了好长时间才搞定。于是写了这篇文章,总结一下。

 

【问题描述】

在Excel中,列的名称是这样一个递增序列:A、B、C、…、Z、AA、AB、AC、…、AZ、BA、BB、BC、…、BZ、CA、…、ZZ、AAA、AAB…。
我们需要将上述列名序列和以下自然数序列相互转换:1、2、3、…。

 

【问题分析】

经过分析,我们不难发现,这是一个26进制和十进制相互转换的问题。序列A-Z依次对应序列1-26。进制转换的基本办法就是“取余法”,换算规则如下:
ABZ = 1*26² + 2 * 26¹ + 26*26°= 676 + 52 + 26 = 754
于是,我们就知道该如何设计一个十进制转换为26进制的算法了。

 

【算法描述】
Step1.[取余] 用指定自然数n除以26,得到一个余数m。如果m = 0,置m←26。
Step2.[转换为字符] 将m映射为字符c,映射规则是{1-26}->{A-Z}。然后将c拼接到26进制值s的左边,也就是置s←c + s。
Step3.[去余降幂] 置n←(n–m)/26。如果n > 0,则回到Step1继续执行,否则进入Step4。
Step4.[结束] 返回s。

按照上述思想,26进制转换为十进制的过程正好是相反的,而且实现起来也更为简单,在此不述。

C#源代码如下:

/// <summary>
/// 将指定的自然数转换为26进制表示。映射关系:[1-26] ->[A-Z]。
/// </summary>
/// <param name="n">自然数(如果无效,则返回空字符串)。</param>
/// <returns>26进制表示。</returns>
public static string ToNumberSystem26(int n){
    string s = string.Empty;
    while (n > 0){
        int m = n % 26;
        if (m == 0) m = 26;
        s = (char)(m + 64) + s;
        n = (n - m) / 26;
    }
    return s;
} 

/// <summary>
/// 将指定的26进制表示转换为自然数。映射关系:[A-Z] ->[1-26]。
/// </summary>
/// <param name="s">26进制表示(如果无效,则返回0)。</param>
/// <returns>自然数。</returns>
public static int FromNumberSystem26(string s){
    if (string.IsNullOrEmpty(s)) return 0; 
    int n = 0;
    for (int i = s.Length - 1, j = 1; i >= 0; i--, j *= 26){
        char c = Char.ToUpper(s[i]);
        if (c < 'A' || c > 'Z') return 0;
        n += ((int)c - 64) * j;
    }
    return n;
}

static void Main(string[] args){
    int[] numbers = { 1, 10, 26, 27, 256, 702, 703 };
    foreach (int n in numbers){
        string s = ToNumberSystem26(n);
        Console.WriteLine(n + "\t" + s + "\t" + FromNumberSystem26(s));
    }
    Console.ReadLine();
}

运行结果如下图所示:


【总结】
一般情况下,各种进制都是以0为起点递增的,例如,八进制(0-7),16进制(0-F)。在本文中,我们设计的26进制是以A为起点的,而不是0,这是主要的不同点。

作者:Lave Zhang
出处:http://www.cnblogs.com/lavezhang/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
非常好的问题!我可以为您提供一个基本的思路: 1. 打开文件,读取每个字符,并记录每个英文字母的出现次数。 2. 计算每个英文字母的频率,即将其出现次数除以总字符数。 3. 将每个英文字母的频率换为十进制形式,并输出。 下面是一个简单的汇编程序,可以实现上述功能。请注意,这个程序是基于 x86 体系结构的,可能需要做一些修改才能在不同的处理器上运行。 ``` section .data filename db "input.txt",0 counts times 26 db 0 total db 0 section .bss buffer resb 1 section .text global _start _start: ; 打开文件 mov eax, 5 mov ebx, filename mov ecx, 0 int 0x80 ; 读取文件 mov ebx, eax read_loop: mov eax, 3 mov ecx, buffer mov edx, 1 int 0x80 ; 判断文件是否结束 cmp eax, 0 je end_read ; 统计字符 cmp byte [buffer], 65 jl not_letter cmp byte [buffer], 90 jg not_letter sub byte [buffer], 65 inc byte [counts + eax - 65] inc byte [total] not_letter: jmp read_loop end_read: ; 计算频率并输出 mov ecx, 26 mov esi, counts mov edi, 0 calc_freq: mov al, byte [esi] mul 100 div byte [total] mov byte [edi], al inc esi inc edi loop calc_freq ; 输出频率 mov eax, 4 mov ebx, 1 mov ecx, counts mov edx, 26 int 0x80 ; 关闭文件 mov eax, 6 int 0x80 ; 退出程序 mov eax, 1 xor ebx, ebx int 0x80 ``` 希望这个程序能够帮助到您!请注意,这只是一个基本的示例程序,您可能需要根据您的具体需求进行修改。同时,也请注意代码中的注释,以更好地理解程序的运行流程。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值