0

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.

Ethan Maness
  • 161
  • 8
  • Note that while the dup is tagged c#, it has language agnostic answer's – chris neilsen Jun 01 '23 at 20:24
  • This is an inaccurate duplicate listing. The linked "duplicate" question only provides half of the answer. I made this question specifically because I was unable to find any resources on stackoverflow regarding the conversion in the opposite direction. I do not have the requisite reputation points to vote to reopen. – Ethan Maness Jun 01 '23 at 20:44
  • actually, that Q&A does include answers that convert from alpha to numeric. – chris neilsen Jun 01 '23 at 21:24
  • Again, the linked question is not asking the same thing as this one. It is specifically about translating from integers in the range 1-16384 to Excel column labels, not the general case conversion between any positive integer and any alphabetic index, and as such this is not a duplicate. You are correct that if you scroll far enough down on that question, you can find a couple C# implementations and an Elixir one for the reverse function, but this is beside the point. – Ethan Maness Jun 01 '23 at 21:43
  • I'll also add that the phrasing of that question makes it exceedingly hard to find for anyone like myself who isn't searching for an Excel-specific answer. I posted this self-answered question specifically because I couldn't find any question on stackoverflow asking about the alpha-to-numeric conversion. – Ethan Maness Jun 01 '23 at 21:45
  • You seem to have missed the point of close as dup. It's more about the answers than the questions. Anyone who is searching this topic that finds _this_ Q first now has a signpost to _that_ Q&A and its cornucopia of answers. BTW, since you wanted to post your own answer, it'd be more discoverable posted on _that_ Q (and deleted here, since exact duplicats answers are not ok) – chris neilsen Jun 01 '23 at 21:56
  • The answer would not have been more discoverable on that Q, since that Q is not discoverable to people searching for this question for the reasons I already addressed. Otherwise, I would have found it in the hour I spent searching before deciding to solve it myself. Not to mention, the fact that the question isn't asking the question I'm answering means people looking for my answer aren't going to click on that question, and certainly aren't going to skim through 57 other unhelpful answers. – Ethan Maness Jun 01 '23 at 22:04
  • Again, you miss the point. I'm _not_ suggesting deleting this, but rather leaving it up, with its signpost to a more comprehensive set of answers. – chris neilsen Jun 01 '23 at 22:15
  • I understand your point just fine. What I am saying is that this is not a duplicate question. Linking to a *similar* question that has somewhat related answers is great, but that is not what the close as duplicate feature is for -- a comment accomplishes the same effect just fine. – Ethan Maness Jun 01 '23 at 22:35
  • You may think that sounds like nitpicking, but the problem with misusing the duplicate vote system is that now, after thoroughly searching for an existing instance of this question, solving it myself, and posting an efficient and broadly-applicable solution for others, I am rewarded with a six month question ban, and any future visitors who have a better solution cannot share where others will find it. – Ethan Maness Jun 01 '23 at 22:35
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/253926/discussion-between-ethan-maness-and-chris-neilsen). – Ethan Maness Jun 01 '23 at 22:36

2 Answers2

0

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 < alpha.length; i++
        result = result * 26 + alpha[i] - 'A' + 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 = ""

    while n > 0
        uint remainder = n % 26
        result = str('A' + (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.

Ethan Maness
  • 161
  • 8
0

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

To convert the alphabet charcter to a number, use: =COLUMN(INDIRECT(A2 & 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) & 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

Ron Rosenfeld
  • 53,870
  • 7
  • 28
  • 60
  • 1
    Note that this is not a question about Excel or its columns, that was merely an example of the type of indexing. – Ethan Maness Jun 01 '23 at 21:19
  • @EthanManess Since you had tagged it with Excel, an assumption was that you were looking for a solution in Excel. In any event, the VBA algorithm can be implemented in many languages. – Ron Rosenfeld Jun 02 '23 at 00:02
  • Apologies, I tagged it as Excel since others with this question might be needing it for Excel applications – Ethan Maness Jun 05 '23 at 21:21