I found several chunks of code on the internet which were supposed to convert a 0-based column number in Excel to a letter, but I could get none of them to work with a value above 25. So here's the code I got working, for everyone's use. Enjoy.


###################################################################### # 7/25/2016 # In: Column index, 0-n. # Out: Letter(s) representing column in Excel. 0=A, 1=B, 25=Z, 26=AA.. +. # # Inspired by http://stackoverflow.com/questions/3302857/algorithm-to- +get-the-excel-like-column-name-of-a-number # 7/25/2016 WORKS! sub excelpos2ltr {my($oldcol)=@_; # Col starts at 0='A' my($procname,$numeric,$ltr,$num2,$outs); $procname="excelpos2ltr"; # Alt method 4. $numeric = $oldcol % 26; $ltr = chr(65 + $numeric); #$num2 = intval($oldcol / 26); # old line $num2 = int($oldcol / 26); if ($num2 > 0) { $outs=excelpos2ltr($num2 - 1) . $ltr; } else { $outs=$ltr; } return $outs; }

If you found any problems please put the code fix as a comment below.

Replies are listed 'Best First'.
Re: Get excel column letter from number
by MidLifeXis (Monsignor) on Jul 26, 2016 at 19:08 UTC

    It might help to realize that the column name is essentially a base-26 number, using A as '0'. Then a div+mod loop while anything is left would only require building a 26 character alphabet. (for all I know, this could be how the XLS utils mentioned above handle it).

    There are a couple of fencepost errors here. Fix coming shortly Ok, this is not quite a base-26 number. The least significant digit is treated slightly different than all other digits.

    sub mlx_xls2col { my $col = shift; my $alphabet = shift || [ 'A' .. 'Z' ]; my $alphabet_size = scalar( @$alphabet ); my $result = ''; my $remainder = $col; while ( $remainder ) { my $letter = $remainder % $alphabet_size; my $adj = length( $result ) ? -1 : 0; # Not quite a base-26 + number $result = $alphabet->[$letter + $adj] . $result; $remainder = int( $remainder / $alphabet_size ); } $result ||= $alphabet->[0]; $result; } print mlx_xls2col( 0 ), "\n"; print mlx_xls2col( 1 ), "\n"; print mlx_xls2col( 2 ), "\n"; print mlx_xls2col( 24 ), "\n"; print mlx_xls2col( 25 ), "\n"; print mlx_xls2col( 26 ), "\n"; print mlx_xls2col( 27 ), "\n"; print mlx_xls2col( 51 ), "\n"; print mlx_xls2col( 52 ), "\n"; print mlx_xls2col( 53 ), "\n"; __DATA__ A B C Y Z AA AB AZ BA BB

    --MidLifeXis

Re: Get excel column letter from number
by Corion (Patriarch) on Jul 26, 2016 at 11:09 UTC
Re: Get excel column letter from number
by haukex (Archbishop) on Jul 26, 2016 at 11:10 UTC

    Hi bulrush,

    Here are a couple of tests, and just for fun my own (horribly inefficient, benchmark included) implementation using Perl's magic string increment:

    #!/usr/bin/env perl use warnings; use strict; sub excelpos2ltr { # by bulrush, https://perlmonks.pair.com/?node_id=1 +168549 my($oldcol)=@_; # Col starts at 0='A' my($procname,$numeric,$ltr,$num2,$outs); $procname="excelpos2ltr"; # Alt method 4. $numeric = $oldcol % 26; $ltr = chr(65 + $numeric); #$num2 = intval($oldcol / 26); # old line $num2 = int($oldcol / 26); if ($num2 > 0) { $outs=excelpos2ltr($num2 - 1) . $ltr; } else { $outs=$ltr; } return $outs; } sub colname { my $n = "A"; $n++ for 1..shift; return $n; } my %tests = ( 0=>"A", 1=>"B", 25=>"Z", 26=>"AA", 27=>"AB", 99=>"CV", 420=>"PE", 479=>"RL", 14557=>"UMX", 285075=>"PERL", ); use Test::More; plan tests => 2 * scalar keys %tests; is excelpos2ltr($_), $tests{$_}, "excelpos2ltr $_ => $tests{$_}" for sort {$a<=>$b} keys %tests; is colname($_), $tests{$_}, "colname $_ => $tests{$_}" for sort {$a<=>$b} keys %tests; done_testing; use Benchmark 'cmpthese'; cmpthese(-5, { # not neccesarily a fair benchmark due to random test data excelpos2ltr => sub { excelpos2ltr(rand(10000)) }, colname => sub { colname(rand(10000)) }, });

    Regards,
    -- Hauke D

Re: Get excel column letter from number
by Anonymous Monk on Jul 26, 2016 at 11:12 UTC

    What's the maximum for column numbers? A simple routine for up to three letters:

    sub ltr { ("A".."ZZZ")[@_] } print ltr(26);

      Simple and elegant given that Excel has a max column of "XFD". I'd modify this to cache the column names and throw a fit if we go too far (eventually, the column cap will be increased or removed):

      sub ltr_cached { state $ltr_cache = ["A".."ZZZ"]; return ($$ltr_cache[$_[0]] or die "column too big: $_[0]") }

      Good Day,
          Dean

      For simplicity and perlness points, an extra ++ to this one... :-)

      Running haukex's test-and-benchmark with AM's ltr() included (without 285075=>'PERL' in the test list), ltr() appears about 10x more efficient than colname(). A four-Z-based ltr(), however, is about 75% less efficient than colname().

      Excel 2007 upped the limit from 2-letter/256-column to 3-letter/16384-column, and that hasn't changed as of Excel 2016, so the more-efficient ZZZ-based ltr() is sufficient for now. :-)

Re: Get excel column letter from number
by dasgar (Priest) on Jul 26, 2016 at 16:54 UTC

    Although it's not zero based, I've been using Number::Latin to convert between column numbers and names. And it's not too difficult to modify input/output of its functions to use zero based numbering scheme for the columns.