I would like to create a function in Mathematica, which returns the equivalent Excel column label (e.g., A, Z, AA, AZ, and so on) given a column number.
I think it can be done with IntegerString[10,26]
, but this representation set of this chars is 0 to 9 and then a to z. However, Excel uses only A to Z.
How can this be done?
Answer
Ok, well, I only needed the inverse function so far and have implemented it as:
FromExcelCol[col_String] := FromDigits[ToCharacterCode[col] - 64, 26]
It runs fine because FromDigits does not complain about characters larger than base-1.
However, the other way round seems to be more tricky. The leading digit runs from 0 to 26 (1 to 27 if you want -> base 27), but only as long as it is leading. Then it runs as a trailing digit from 1 to 26.
I have not found an elegant, non-iterative solution so far. I was hesitating to paste my (ugly but working) piece of code, but maybe it encourages others to look for a nice solution. :)
ToExcelCol[n_Integer] := Module[{subtract, num, base},
subtract = Accumulate[Power[26, #] & /@ (Range[7] - 1)];
base = Position[subtract, x_ /; x > n, {1}, 1][[1, 1]] - 1; (*find largest number which is <= base ... I think there are better alg. for this but I don't have them at hand, sorry*)
num = n - subtract[[base]];
StringJoin@PadLeft[FromCharacterCode /@ (IntegerDigits[num, 26] + 65), base, "A"]
]
Basically, what you have to do and what this function does, is subtract 26^0 if n > 26^0, then subtract 26^1 if n > 26^1+26^0 and so on. Finally pad the result to x digits with the largest 26^x+26^(x-1)+....
I have tried but I could not make a satisfying solution, so I kindly invite you to improve this piece of code. I still find that it is too iterating (with the lookup table generated in the first step). I have also thought of treating part of the number as base 27 and the other part as base 26, but well... not tonight anymore. :)
EDIT: Jacob just figured out what I was looking for: You can determine the number of digits in the final column name with Log[26, 25 (n + 1)]
. So, here is the simplified version:
ToExcelCol2[n_Integer] := Module[{num, base},
base = Floor[Log[26, 25 (n + 1)]];
num = n - Total[Power[26, #] & /@ (Range[base] - 1)];
StringJoin@PadLeft[FromCharacterCode /@ (IntegerDigits[num, 26] + 65), base, "A"]]
You can condense this into a one-liner without Module of course, but I'll leave that up to you.
Comments
Post a Comment