|
PerlでExcelアドレスA1タイプの列表記を扱う
2024/06/01 | ||||||||||||
| [Prev] [Next] [Top] , Perl [Prev] [Next] , [Perl Top] | ||||||||||||
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] [Next] , [Perl Top] |