Excel列名変換問題を解いてみた。

Excel列名変換問題で第2回社内プログラミングコンテストを開催してみた(前編) - give IT a tryにたまたまたどり着いて、「そういえば最近Perl使っていないな(というかコード書いていないな)」と思ったので、まずは問題1に挑戦してみた。

問題1: Excel列名変換問題

    仕様
        入力されたアルファベットを数字に変換する。
        変換ルールはExcelの列名と同等。
        例) A=1、B=2、Z=26、AA=27、XFD=16384

    起動時引数
        [0] アルファベット (A〜ZZZZ...[上限なし])*2

    実行例
        ExcelColConv.pl A → 1
        ExcelColConv.pl AA → 27

思考ロジックを整理しておくと

  • A〜Zを取り扱うので、要は26進数の10進数変換。
  • A〜Zを1〜26にどうやって変換するか?
    • 文字コード変換を活用するとすっきりしたコードになりそう。だけど、大学生の時(1x年前)に川崎くんに実装の考え方を聞いただけで、コードを見たことも書いたこともないので、調べないとダメそう。
    • あまりに久しぶりのPerlなので、文法とか調べていたらハッシュ型の変数なるものを発見。これは便利そう。
  • Perlでべき乗の演算子しらないな〜、と思って調べた。

で、作ったコードが以下。

my @val_array;
my $val_sum = 0;
my %hash;
%hash = (a => 1,b => 2,c => 3,d => 4,e => 5,f => 6,g => 7,h => 8,i => 9, j => 10,k => 11,l => 12,m => 13,n => 14,o => 15,p => 16,q => 17,r => 18,s => 19,t => 20,u => 21,v => 22,w => 23,x => 24,y => 25,z => 26);

my $input  = $ARGV[0];
my $len = length( $input );

# 入力文字列の順を逆にする
for ( my $i = 0 ; $i < $len ; $i++){
	$val_array[ $i ] = substr( $input , $len - $i - 1 , 1 );
}

#1桁ずつ26進数として処理
for ( my $j = 0 ; $j < $len ; $j++){
    my $conved_val = $hash { $val_array [ $j ] } ;
	$val_sum = $val_sum + ( $conved_val * (26 ** $j)) ; 
}

print "value : $val_sum \n";

ここまで作って答え合わせ。
Excel列名変換問題で第2回社内プログラミングコンテストを開催してみた(前編) - give IT a tryの答え(上位3作品)を見ると、

  • 第1位:ハッシュ変数による変換。但し、ループが1回
  • 第2位:文字コード変化を活用した変換。

そうそう、こうやってみたかったんですが、ordっていう関数があるんですね。で、Aのアスキーコードが65だから、64引くと。ちょっと調べたら、文字コードから文字にするにはchar関数を使えば良いようです。これは第2問に使えそうです。

    # Convert A-Z to a number
    my $ascii_code = ord($columns[$i]);
    # subtract 64 (to convert A to 1 B to 2 etc)
    my $value = $ascii_code - 64;

久しぶりにPerlの基礎を確認するのに便利だったページをいくつかメモしておく。

Perl入門ゼミ
特にこのページ

後は、MacPerlを使う際の注意点。UnicodeとかCR改行コードでハマるとは思いませんでした。
http://d.hatena.ne.jp/hornistyf/20080421/1211981662