最近、VBAに触れることが多くなってきましたが、あの独特の構文になかなか慣れないので、Perlと対応させてみました。突っ込み歓迎。
いずれこっちにもまとめます。http://bd.nomupro.com
基本仕様
型と変数
Perlには数値型や文字列型のような型はありませんが、スカラ変数、配列変数、ハッシュ変数の様な、変数に格納する値の種類(単一の値、複数の値、キーと値がペアになっている値)によって変数名が異なります。また、変数はmy、our等で宣言し、同時に初期化することが出来ます。
VBAでは、型がたくさんあります。Excelを扱う為に、セルを扱うCells型やSheet型等、特徴的な型があります。
また、変数はDimで変数宣言をします。同時に初期化は出来ません(のはず。。。)。
【Perl】
# コメントは#(井げた)で書きます my $scalar = "hoge";my $scalar = 100;my $scalar = 20.0; my @array = (10, 20, 30); my %hash = (one => 1, two => 2, three => 3);
【VBA】
'コメントは'(シングルクォート)で書きます Dim i As Interger 'Integer型 Dim str As String 'String型 Dim select As Range 'Range型 i = 10 str = "string" Set select = Cells(1,1) 'オブジェクト型はSetを使う
定数
Perlではconstantプラグマを使います。VBAではDimの代わりにConstを使用し、同時に初期化を行います。
【Perl】
use constant VAR => "HOGE"; print HOGE, "\n";
【VBA】
Const STR As String = "HOGEHOGE"
if〜elsif〜else
構造化プログラミングの基本、分岐です。
Perlではなぜかelse ifではなくelsifです。
【Perl】
標準入力から文字列を読み込み、偶奇を判定するプログラムです。
my $number = <STDIN>; chomp($number); if($number !~ /^[0-9]+$/){ print $number, " is not number\n"; }elsif($number == 0) { print $number, " is zero\n"; }elsif($number % 2 == 0){ print $number, " is even\n"; }else{ print $number, " is odd\n"; }
【VBA】
セルから読み取り、偶奇を判定します。
Sub func() Dim value As Variant value = Cells(1, 1).value If Not IsNumeric(value) Then Cells(2, 1) = value & " is not number" Else Dim number As Integer number = Cells(1, 1) If number = 0 Then Cells(2, 1) = number & " is zero" ElseIf number Mod 2 = 0 Then Cells(2, 1) = number & " is even" Else Cells(2, 1) = number & " is odd" End If End If End Sub
for、foreach、while
次は反復です。
【Perl】
Perlには色々な反復の書き方がありますね。1..10みたいな書き方、素晴らしいです。
lastでループの中断、nextでループスキップです。
for(my $i = 0; $i < COUNT; $i++) { print $i; } print "\n"; foreach my $i(0..COUNT - 1) { print $i; } print "\n"; my $i = 0; while($i < COUNT) { print $i++; } print "\n";
【VBA】
VBAのFor文は、ループの終了合図として、Next <カウンタ変数>という記述をするのが特徴的です。
ちなみに、VBAにはPerlのnextはありません。ループの外側にラベルを貼ってGoToします。
'B列を判定列とし、skipが入っていた場合は次の行へ、 'endが入っていた場合は、ループを終了、 'それ以外はHOGEを入れていく Sub func2() Dim i '行の最後までループする For i = 1 To Rows.Count If Cells(i, 2) = "skip" Then: GoTo CONTINUE Cells(i, 1).value = "HOGE" If Cells(i, 2) = "end" Then: Exit For CONTINUE: Next i End Sub
VBAにもWhileがありますが、Do-Loopが汎用的なのでこちらを使う方がいいでしょう。
'10回ループを回し、HOGE + カウンタ値を入力していく関数 Sub func_do() Dim counter As Integer counter = 1 Do While counter < 10 Cells(counter, 1) = "HOGE" & counter counter = counter + 1 Loop End Sub
コレクションに対しては、For Eachを使うことが出来ます。
'選択範囲に対して、文字列を入力していく関数 Sub selection_input() Dim ss As Range For Each ss In Selection ss.value = "選択範囲です" Next End Sub
関数
関数の基本、引数の渡し方、戻り値です。
【Perl】
Perlではsubで関数を定義します。戻り値はreturnを付けても付けなくてもどちらでも構いません。また、引数は特殊変数@_に入ります。
関数の呼び出しは 関数名(引数); です。
print plus(10,20), "\n"; sub plus { my($val1, $val2) = @_; $val1 + $val2; }
【VBA】
VBAには関数定義の方法がSubとFunctionの2つあります。引数を返して欲しい場合はFunctionを使用します。Functionで定義した関数は、ユーザ定義関数として、エクセルの表から使うことが出来ます。定義した関数はCallを使って呼び出します。
'main関数から関数を呼び出す Sub main() Call func_Sub(Range("A1").value) End Sub Sub func_Sub(str As String) Range("A2").value = str End Sub
以下の様に、他の関数から呼び出すことも可能ですが、セルへ =func_Function(10,20) と入力することで、ユーザ定義関数として呼び出すことも可能です。
'main関数から関数を呼び出す Sub main() Dim i As Integer i = func_Function(10, 20) End Sub Function func_Function(value1 As Integer, value2 As Integer) func_Function = value1 + value2 End Function
配列操作
配列定義、配列アクセス
【Perl】
Perlは、ご存知の通り、コンテキスト(文脈)によって挙動の変わる言語です。配列の場合、スカラコンテキストとして解釈されると、配列の要素数を返す特徴を持っています。
# 配列を初期化するには空配列()を代入する my @array = (); # 配列の要素数は予め決める必要は無い @array = (10, 20, 30); # 配列の0番目にアクセスする(出力:10) print $array[0], "\n"; # 配列の最後の添字を取得する(出力:2) print $#array, "\n"; # 配列の要素数を取得する(出力:3) print scalar(@array), "\n";
【VBA】
Dim strings(10) As String '10個の配列を宣言 strings(0) = "HOGE" MsgBox strings(0) '配列の0番目にアクセスする MsgBox UBound(strings) 'UBound関数で配列のインデックスの最大値を取得
VBAはPerlに比べ、配列の扱いが少し面倒です。
静的配列、動的配列が存在し、静的配列の場合、配列数は一度定義すると変更できません。以下は、静的配列の例と、ファイルから1行ずつ読み込み、動的配列に格納していく例を示します。
Sub func_array() Dim strings(10) As String '10個の配列を宣言 For i = 0 To UBound(strings) 'UBound関数で配列のインデックスの最大値を取得 strings(i) = "HOGE" & i + 1 Next i For i = 0 To UBound(strings) Cells(i + 1, 2) = strings(i) Next i End Sub Sub func_array2() Dim strings() As String '動的配列を宣言 Dim count As Integer count = 0 Open "test.txt" For Input As #1 'ファイルから読み込む Do Until EOF(1) ReDim Preserve strings(count) 'Preserveで配列数のみを変更 '(Preserveでない場合初期化される) Line Input #1, strings(count) count = count + 1 Loop Close 1 For i = 0 To UBound(strings) Cells(i + 1, 1) = i + 1 & ":" & strings(i) Next i End Sub
文字列操作
文字列の結合
print "HOGE"."PGR", "\n"; # 2行に渡る場合改行を入れることが可能 print "HOGE" ."PGR", "\n"; # 変数の結合も可能 my($str1, $str2) = ("HOGE", "PGR"); print $str1.$str2, "\n";
Sub func_string() MsgBox "HOGE" & "PGR" '2行に渡る場合は「_」を使用し改行する MsgBox "HOGE" _ & "PGR" Dim str1 As String, str2 As String str1 = "HOGE": str2 = "PGR" '変数の場合も同じ MsgBox str1 & str2 End Sub
ファイル操作
ファイルから1行ずつ読み込み、行数を付与してファイルへ書き出してみます。
【Perl】
3引数のopenは常識ですよね。第2引数のモード指定で書き込み、読み込みを制御します。
use constant READ_FILEPATH => "test.txt"; use constant WRITE_FILEPATH => "test2.txt"; open(my $rfh, "<", READ_FILEPATH); open(my $wfh, ">", WRITE_FILEPATH); my $num = 0; while(<$rfh>) { chomp; # 書き込み用にオープンしたファイルハンドルを渡すことで書き込む print $wfh ++$num.":".$_, "\n"; } close($rfh); close($wfh);
【VBA】
VBAの場合、ファイルハンドルは数字です。また、モードは、Input(読み込み)、Output(書き込み)、Append(追記)、Random(ランダムアクセス)、Binary(バイナリ)の5種類あります。
Sub func_file() Const READ_FILEPATH As String = "test.txt" Const WRITE_FILEPATH As String = "test2.txt" Open READ_FILEPATH For Input As #1 '読み込み用ファイルハンドル Open WRITE_FILEPATH For Output As #2 '書き込み用ファイルハンドル Dim num As Integer num = 1 Do Until EOF(1) Dim str As String Line Input #1, str Print #2, num & ":" & str num = num + 1 Loop Close End Sub