如何在正整数和字母索引/计数值之间转换

huangapple go评论64阅读模式
英文:

How to convert between positive integers and alphabetic index/counter values

问题

我正在为一个使用字母索引(或者说子索引)的系统编写代码,并需要一种将整数转换为字母索引以及反向转换的方法,用于排序和确定范围大小等操作。请注意,这里的“字母索引”是指类似于Excel用于列标签的系统,即从A、B、...、Y、Z开始,然后进入AA、AB、...、ZY、ZZ,然后进一步到AAA、AAB、...,以此类推。这些索引需要从A = 1开始,递增1。因此,Z = 26,AA = 27,依此类推。

例如,如果给定字符串“ABC”,将其转换为整数的函数返回值将等于从A到ABC的字母索引数量,包括A和ABC。在这种情况下,A-Z有26个索引,AA-ZZ有26*26个索引,AAA-ABC有29个索引(26+3),总共是731个索引。这是一个简单的字符串迭代问题。

反过来更加复杂。给定整数731,整数转字母索引的函数将返回第731个字母索引,即“ABC”。这需要一些特殊的算法。

需要注意的是,这与简单的十进制到二十六进制或反之的转换问题不同,因为在这种系统中,A是0,AA也是0,而26是BA。

在未能找到后者的解决方案后,我自己想出了一种算法,并在下面的答案中发布了它,以供其他有类似需求的人使用。

编辑:如果您特别是在Excel中使用这个功能来转换列名,那么Excel内置了相应的函数。这个问题是针对一般情况下的字母索引。

英文:

I'm writing code for a system that uses alphabetic indices (well, sub-indices rather), and need a way to convert to and from integers for things like ordering and determining the size of a range. To be clear, by "alphabetic indices" I mean a system like Excel uses for its column labels, i.e. start with A, B, ..., Y, Z, and then go to AA, AB, ..., ZY, ZZ, then on to AAA, AAB, ..., you get the idea. The indices need to start at A = 1, and increment by one. So, Z = 26, AA = 27, etc.

For example, if given the string "ABC" the alpha-to-integer function return value would be equal to the number of alphabetic indices from A to ABC, inclusively. In this case, that's 26 for A-Z, 26*26 for AA-ZZ, and 29 (26+3) for AAA-ABC, for a total of 731. This one is a simple problem of iterating over the string.

Going the other way is harder. Given the integer 731, the integer-to-alpha function would return the 731st alphabetic index, which is "ABC". This requires some funky arithmetic.

Notably, this is not the same as a simple base-10 to base-26 conversion problem or vice versa, because in such a system, A is 0, AA is also 0, and 26 is BA.

After being unable to find a solution for the latter of the two functions, I have come up with an algorithm myself and have posted it as an answer below, for anyone else with a similar need.

EDIT: If you are specifically using this in Excel to convert column names, there are built-in functions for that. This is for general-case alphabetic indexing.

答案1

得分: 0

以下是已翻译的部分:

Alpha to Index

使用Horner's method以最小化所需的操作次数。

uint alphaToIndex(string alpha)

    uint result = 0

    for i = 0; i < alpha.length; i++
        result = result * 26 + alpha[i] - 'A' + 1

    return result

Index to Alpha

这个方法有点奥秘。在这里,str()将整数转换为单字符字符串,而int()将布尔值转换为整数。这还假设模运算符%产生严格正值,即-1 % 26 == 25

string indexToAlpha(uint n)

    string result = ""

    while n > 0
        uint remainder = n % 26
        result = str('A' + (remainder - 1) % 26) + result
        n = n / 26 - int(remainder == 0)
    
    return result

请注意,如果您的编程语言支持可变字符串,那么将每个字符附加到字符串末尾,然后在最后翻转字符串会更快,而不是创建一个新字符串,并将字符添加到当前字符串的开头。

英文:

Here's are the fastest and cleanest general algorithms I was able to come up with, in pseudocode since this can apply to any language. This assumes that the character encoding groups the characters A-Z together, in order.

Alpha to Index

Uses Horner's method to minimize the number of operations needed.

uint alphaToIndex(string alpha)

    uint result = 0

    for i = 0; i &lt; alpha.length; i++
        result = result * 26 + alpha[i] - &#39;A&#39; + 1

    return result

Index to Alpha

This one is a bit more arcane. Here, str() converts an integer to a single-char string, and int() converts a boolean to an integer. This also assumes that the modulus operator % gives strictly positive values, i.e. -1 % 26 == 25.

string indexToAlpha(uint n)

    string result = &quot;&quot;

    while n &gt; 0
        uint remainder = n % 26
        result = str(&#39;A&#39; + (remainder - 1) % 26) + result
        n = n / 26 - int(remainder == 0)
    
    return result

Note, if your language has mutable strings, it is faster to append each character onto the end and then flip the string at the end, rather than create a new string with the character prepended onto the current string.

答案2

得分: 0

Sure, here are the translated parts:

如果您的数字保证在范围 1..16384 内,您可以使用 Excel 的 =TEXTBEFORE(ADDRESS(1,A1,2)," $ ") 公式,其中 A1 包含要转换的数字。

要将字母字符转换为数字,请使用:=COLUMN(INDIRECT(A2 & 1))

如果您的值可能大于 16,384,那么您可以尝试以下两个 VBA 例程来进行转换:

Option Explicit

Function NumberToLetterSequence(Number As Long) As String
    Dim n As Long
    Dim c As Byte
    Dim s As String

    n = Number
    Do
        c = ((n - 1) Mod 26)
        s = Chr(c + 65) & s
        n = (n - c) \ 26
    Loop While n > 0
    NumberToLetterSequence = s
End Function

Function LetterSequenceToNumber(Letters As String) As Long
    Dim n As Long
    Dim s() As String
    Dim v As Variant
    Dim i As Long
    
ReDim s(1 To Len(Letters))
For i = 1 To Len(Letters)
    s(i) = Mid(Letters, i, 1)
Next i

For i = 1 To UBound(s)
    n = n + (Asc(s(i)) - 64) * 26 ^ (UBound(s) - i)
Next i
    
LetterSequenceToNumber = n

End Function

(Note: The translation retains the original code formatting and structure.)

英文:

If your numbers are guaranteed to be in the range 1..16384, you can make use of Excel with =TEXTBEFORE(ADDRESS(1,A1,2),&quot;$&quot;) where A1 contains the number to be converted.

To convert the alphabet charcter to a number, use: =COLUMN(INDIRECT(A2 &amp; 1))

If your values might be greater than 16,384, then you can try these two VBA routines to convert back and forth:

Option Explicit

Function NumberToLetterSequence(Number As Long) As String
    Dim n As Long
    Dim c As Byte
    Dim s As String

    n = Number
    Do
        c = ((n - 1) Mod 26)
        s = Chr(c + 65) &amp; s
        n = (n - c) \ 26
    Loop While n &gt; 0
    NumberToLetterSequence = s
End Function

Function LetterSequenceToNumber(Letters As String) As Long
    Dim n As Long
    Dim s() As String
    Dim v As Variant
    Dim i As Long
    
ReDim s(1 To Len(Letters))
For i = 1 To Len(Letters)
    s(i) = Mid(Letters, i, 1)
Next i

For i = 1 To UBound(s)
    n = n + (Asc(s(i)) - 64) * 26 ^ (UBound(s) - i)
Next i
    
LetterSequenceToNumber = n

End Function

huangapple
  • 本文由 发表于 2023年6月1日 08:05:53
  • 转载请务必保留本文链接:https://go.coder-hub.com/76377947.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定