PerlでExcelアドレスA1タイプの列表記を扱う
2024/06/01 | ||||||||||||
[Prev]
[Next]
[Top]
,
Perl
[Prev]
| ||||||||||||
ExcelのA1アドレス表記はややこしい
方法1: 餅は餅屋: Excel自身に変換してもらう
#!perl -w use Win32::OLE; use strict; { # OLEでExcel起動 my $excel = Win32::OLE->new("Excel.Application"); # Bookオブジェクト作成 my $book =$excel->Workbooks->Add(); # 列1から最大の16384までA1表記アドレスを取得 for (my $col_dec=1; $col_dec<=16384; $col_dec++) { # Cell(1行目,指定列)のAddressプロパティを取得 my $addr_A1 = $book->Worksheets(1)->Cells(1,$col_dec)->{Address}; # 戻り値は '$A$1' なので列表記部を抽出 if ($addr_A1 =~ /\$(\w+)\$/) { my $col_A1 = $1; # A1タイプ列表記抽出 print "$col_dec\t$col_A1\n"; } } # Excelクローズ $excel->Quit(); } 1 A 2 B 3 C ...中略... 16383 XFC 16384 XFD 方法2: 力こそパワー: Aから順番に変換する
#!perl -w use strict; { for (my $idx=1; $idx<=16384; $idx++) { print "$idx\t",convert_dec_to_A1($idx),"\n"; } } sub convert_dec_to_A1 { my ($col_dec) = @_; # 各桁のカウントステータス保持配列(列の最大値は16384→最大桁3) my @digits = (0,0,0); # 桁0,1,2のカウント値保持 # 桁上げ判定 my @carry; # 列1から最大の変換対象列までA1表記アドレスを取得 for (my $col_num=1; $col_num<=$col_dec; $col_num++) { # 桁上げ判定初期化(最下位桁は常にカウント) @carry = (1,0,0); # 第1桁:Carry判定 $carry[1]=1 if ($digits[0]==26); # 第2桁:Carry判定 $carry[2]=1 if (($digits[1]==26) and ($carry[1]>0)); # 各桁のカウントアップ for (my $i=0; $i<@digits; $i++) { $digits[$i]++ if ($carry[$i]>0); $digits[$i]=1 if ($digits[$i]>26); # 26(Z)を超えたら'A'に戻す } } # カウント終了後数値を文字表記に変換する。1をAとすれば、AのASCコードが65なので # オフセットとして64を足し、chr関数で文字変換 my $col_A1 = ''; for (my $i=0; $i<@digits; $i++) { if ($digits[$i] > 0) { # 各桁の数値が0より大きければ文字変換して結合 $col_A1 = chr($digits[$i]+64).$col_A1; } } # 変換結果を戻す return($col_A1); } 方法3: ようやく真面目に: 各桁独立の変換
#!perl -w use strict; { for (my $idx=1; $idx<=16384; $idx++) { print "$idx\t",convert_dec_to_A1($idx),"\n"; } } sub convert_dec_to_A1 { my ($col_dec) = @_; # 各桁の値初期化 my @digits = (0,0,0); # 計算値保持 # 第0桁 # - 26除算した剰余 # - 0のときは26とする $digits[0] = $col_dec % 26; $digits[0] = 26 if ($digits[0] < 1); # 第1桁 # - 第0桁の開始値(26**0)を引いてから26除算の商 # - 商が26を超えた場合は # - 更に26除算した剰余 # - 0のときは26とする $digits[1] = int(($col_dec - 26**0) / 26**1); if ($digits[1] > 26) { $digits[1] = $digits[1] % 26; $digits[1] = 26 if ($digits[1] < 1); } # 第2桁 # - 第1桁の開始値(27=26**0 + 26**1)を引いてから26**2除算の商 # - 商が26を超えた場合は # - 更に26除算した剰余 # - 0のときは26とする $digits[2] = int(($col_dec - (26**0 + 26**1)) / (26**2)); if ($digits[2] > 26) { $digits[2] = $digits[2] % 26; $digits[2] = 26 if ($digits[2] < 1); } # 数値を文字表記に変換する。1をAとすれば、AのASCコードが65なので # オフセットとして64を足し、chr関数で文字変換 my $col_A1 = ''; for (my $i=0; $i<@digits; $i++) { if ($digits[$i] > 0) { # 各桁の数値が0より大きければ文字変換して結合 $col_A1 = chr($digits[$i]+64).$col_A1; } } # 変換結果を戻す return($col_A1); } #!perl -w use strict; { for (my $idx=1; $idx<=16384; $idx++) { print "$idx\t",convert_dec_to_A1($idx),"\n"; } } sub convert_dec_to_A1 { my ($col_dec) = @_; # 各桁の値初期化 my $digits = []; # 計算値保持 my $init = 0; # 各桁の計算オフセット初期値 my $div = 0; # 除算分母初期値 # 引数値の最大桁見積もり my $maxdigit = 0; $maxdigit++ while($col_dec/(26**$maxdigit) > 26); # 各桁の計算 for (my $i=0; $i<=$maxdigit; $i++) { $div = 26**$i; # 計算桁除算分母 $digits->[$i] = 0; # 計算桁初期値 $init += int(26**($i-1)); $digits->[$i] = int(($col_dec - $init) / $div); if ($digits->[$i] > 26) { $digits->[$i] = $digits->[$i] % 26; $digits->[$i] = 26 if ($digits->[$i] < 1); } } # 数値を文字表記に変換する。1をAとすれば、AのASCコードが65なので # オフセットとして64を足し、chr関数で文字変換 my $col_A1 = ''; for (my $i=0; $i<@{$digits}; $i++) { if ($digits->[$i] > 0) { # 各桁の数値が0より大きければ文字変換して結合 $col_A1 = chr($digits->[$i]+64).$col_A1; } } # 変換結果を戻す return($col_A1); } | ||||||||||||
Notes | ||||||||||||
2024/06/02: 表記及び変数名修正、実行時間追記 2024/06/01: 初版 Copyright(C) 2024 Altmo
本HPについて | ||||||||||||
[Prev]
[Next]
[Top]
,
Perl
[Prev]
|