Excel VBAの基本
2021/02/21更新
目次
はじめに
Excel VBAのごく基本的な部分をチートシートとしてまとめた。私自身と同じく「他のプログラミング言語でプログラミングの経験があるが、Excel VBAの経験は無いので、まずは触りだけ理解したい」という方を想定読者としているため、プログラミングのしくみや基礎的な用語の説明など、プログラミング初心者向けの内容は記載していない。
ここに記載の内容を習得するだけでも、VBAを使わない場合に比べればいろいろなことができるようになると思われるが、市販のExcel VBAの解説書の厚さを見て分かる通り、実際にはもっと遥かに複雑で高等なことが可能である。このページで不足している点や触れられていない点については、適宜解説書や他のリファレンスサイトを参照していただきたい。
基本
記述方法
VBAは、VBE(Visual Basic Editor)を使って記述する。VBEを表示するには、事前に「オプション」>「リボン」のユーザー設定で「開発」タブを表示しておく必要がある。開発タブ上の「Visual Basic」ボタンをクリックするとVBEが起動する。
VBEの左上の「プロジェクト」には、現在開いているブックとそこに含まれるシートやモジュールが表示される。ブックを右クリックして「挿入」>「標準モジュール」を選択すると、標準モジュールを追加できる。この標準モジュールに、後述のSubプロシージャやFunctionプロシージャを記述していく。一つの標準モジュールには複数のプロシージャを記述できる。また、複数の標準モジュールを追加することもできる。
モジュールには、標準モジュールの他にも「Microsoft Excel Objects」「フォームモジュール」「クラスモジュール」がある。
実行方法
Subプロシージャを記述した後、上のツールバーにある再生マークのボタンを押すと、表示中の標準モジュールに含まれるプロシージャを実行できる。標準モジュールにSubプロシージャが1つしか含まれていない場合は、そのSubプロシージャが実行されるが、複数含まれている場合は選択画面が表示される。また、引数が必要なSubプロシージャやFunctionプロシージャはここでは実行できない。
また、後述の方法で、ワークシート上に配置したボタンをクリックしてプロシージャを実行することもできる。
デバッグ
VBEの「表示」>「イミディエイトウィンドウ」を選択すると、イミディエイトウィンドウが表示される。ここにはプロシージャ内でDebug.Print
によって出力した値が表示されるため、変数の確認などに便利である。
基本文法
プロシージャ
戻り値を返さないサブルーチンのことをSubプロシージャという。通常マクロというと、この一つ一つのSubプロシージャのことを言う。Subプロシージャは以下のように記述する。
Sub myProcedure() … End Sub
同じモジュール内の他のプロシージャから呼び出すには、Call myProcedure
または単にmyProcedure
と書けばよい。
引数を受け取るには以下のようにする。()
の中に後述の変数宣言と似た記法で引数名と型を指定すればよい。なお、このように記述すると引数は参照渡しとなるので注意が必要である。値渡しにするには、それぞれの引数名の前にByVal
というキーワードを付ける必要がある。逆に、参照渡しであることを明示するためにByRef
というキーワードも存在する。
Sub dialog(name As String, age As Integer) MsgBox name & vbLf & age End Sub '呼び出し側 Sub myProcedure() dialog "Excel太郎", 30 End Sub
Subプロシージャを途中で終了するには、Exit Sub
と記述する。
Sub myProcedure() Dim ans As Integer ans = MsgBox("実行してよろしいですか?", vbOKCancel + vbQuestion) If ans = vbCancel Then Exit Sub … End Sub
Subプロシージャに対して、戻り値を返すユーザー定義関数のことをFunctionプロシージャという。Functionプロシージャは以下のように記述する。
Function sum(a As Integer, b As Integer) As Integer sum = a + b End Function '呼び出し側 Sub myProcedure() Dim x As Integer x = sum(2, 3) MsgBox x End Sub
1行目の(~)
の後に戻り値の型を指定する。Function名は同時にプロシージャ内で戻り値となる変数名にもなっているのが独特である。また、Subプロシージャと同様にByVal
、ByRef
キーワードが使用でき、デフォルトは参照渡しである。
SubプロシージャとFunctionプロシージャの呼び出し方法を見ると、Functionプロシージャには()
を付けて呼び出しているのが分かる。このように、VBAで関数やメソッドを実行する場合、戻り値を使う場合は()
をつけて、使わない場合は()
をつけない、というルールがある。分かりやすい例として、後述のMsgBox
などがある。()
に関しては、以下の外部リンクが詳しい。
コメント
'
から行末までがコメントとなる。
'ここはコメント
コードの改行
VBAでは、C言語やJavaScriptにおける;
に相当するような行区切り文字がないため、基本的に1行に1つの文を書く。1行の途中で改行するには、末尾に_
を書く。
msg = "とても長い行とても長い行とても長い行とても長い行" _ & "とても長い行とても長い行とても長い行とても長い行" _ & "とても長い行とても長い行とても長い行とても長い行"
変数宣言
変数はDim
で宣言し、As
で型を指定する。
'Integer型の変数hogeを宣言。 Dim hoge As Integer '2個以上の変数をまとめて宣言することもできるが、変数ごとにAsの指定は必要。 Dim fuga As String, piyo As String
変数名には半角英数字の他、日本語も使うことができる。記号は_
のみ使用可能で、先頭は数字と_
以外でなければならない。大文字小文字は区別されない。
基本的な型には以下のようなものがある。
型名 | 意味 |
---|---|
Boolean | 真偽値( |
Integer | 符号付き2バイト整数(-32768~32767) |
Long | 符号付き4バイト整数(-2147483648~2147483647) |
Double | 倍精度浮動小数点数 |
String | 文字列 |
これ以外にも、オブジェクトを受け取る場合は、そのオブジェクト名を型として指定する。また、セルの値など、任意の値を受け取る可能性があるものはVariant
という特殊な型を使うことができる。
変数への値の代入は=
を使う。
'変数hogeに値1234を代入。 hoge = 1234
Workbook
、Worksheet
、Range
などのオブジェクトの場合は、参照渡しにするため、Set
を使う必要がある。
'Workbookオブジェクトを代入。 Set myWorkbook = Workbooks("myWorkbook.xlsx")
変更されない(再代入されない)値については、以下のような定数宣言を行なうこともできる。
Const MaxVal As Integer = 1000
数値
数値の四則演算には、他の多くの言語と同じく+
、-
、*
、/
が使えるほか、a \ b
でa÷bの商、a Mod b
でa÷bの余りを取得できる。
C言語やJavaScriptなどにおけるi++
やi--
のようなインクリメントとデクリメントの演算子は存在しない。代入文と加減演算子を使ってi = i + 1
やi = i - 1
とそれぞれ書く必要がある。
基本的な数学関数としては、以下のようなものが使用できる。
関数 | 意味 |
---|---|
|
|
|
|
|
|
|
|
|
|
| eの |
|
|
| 0以上1未満の乱数を返す。 |
|
|
|
|
|
|
|
|
文字列
文字列リテラルは、ダブルクォート"~"
で囲って記述する。また、文字列の結合は&
を使う。
myStr = "これは" & "文字列" 'myStrは「これは文字列」となる。
文字列リテラルの中でダブルクォート自体は""
と記述する。
myStr = "文字列は""hoge""と記述して下さい。" 'myStrは「文字列は"hoge"と記述して下さい。」となる。
改行やタブ文字は、定数として定義されているので、それを連結して使う。
'改行文字(0x0A) myStr = "ここで" & vbLf & "改行します。" 'タブ文字(0x09) myStr = "タブ文字は" & vbTab & "です。"
「0x0D 0x0A」に対応したvbCrLf
も存在するが、ダイアログに表示するメッセージの改行やセル内の改行には基本的にvbLf
を使う。
基本的な文字列操作としては、以下のようなものが可能である。
'文字列の分割 Dim items As Variant items = Split("hoge/fuga/piyo", "/") MsgBox items(0) ' "hoge" MsgBox items(1) ' "fuga" '文字列の検索 MsgBox InStr("hogefuga", "fuga") ' 5 MsgBox InStr("hogefuga", "piyo") ' 0 '文字列の置換 MsgBox Replace("hogefuga", "hoge", "piyo") ' "piyofuga"
条件分岐
if文は以下のように記述する。
If ○○ Then … ElseIf ○○ Then … Else … End If
○○には条件式を記述する。比較演算子は、他の多くの言語と同じく<
、<=
、>
、>=
が使えるが、等価演算子は=
(等しい)と<>
(等しくない)である。また、論理演算子はAnd
、Or
、Not
である。
If x = 10 And y <> 0 Then … End If
Like
演算子を使うと文字列に対してワイルドカード等を用いたパターンマッチを行なうことができる。
If str Like "abc?" Then ' abcの後に1文字 If str Like "abc*" Then ' abcの後に0文字以上 If str Like "abc#" Then ' abcの後に数字1文字 If str Like "abc[x-z]" Then 'abcの後にx、y、zのいずれか1文字 If str Like "abc[!x-z]" Then 'abcの後にx、y、z以外の1文字
ElseIf
、Else
がない場合で、しかも間の文が1つしかないときは、1行で記述することもできる。
If i = 5 Then Exit For '以下と同じ If i = 5 Then Exit For End If
くり返し
基本的なくり返しには以下のような記法がある。
'iを1から10まで変化させてくり返し Dim i As Integer For i = 1 To 10 … 'くり返しから抜ける If i = 5 Then Exit For Next i '条件が真である間くり返し Do While x < 10 … 'くり返しから抜ける If x = 5 Then Exit Do Loop
For i = 1 To 10
の部分をFor i = 1 To 10 Step 2
などとするとカウンタ変数の増分を指定できる。Next i
はカウンタ変数を省略してNext
だけでもよい。Do While ~
のWhile ~
を省略してDo
だけにすると、無限ループとなる。
次のループへ移る命令はVBAでは存在しないため、GoTo
を使って以下のように記述するしかない。また、多重ループを抜ける場合もこのようにする。
For i = 1 To 10 'ループ末尾へジャンプすることで、次のループへ移る。 If i = 5 Then GoTo EndOfLoop … 'ループ末尾にラベルを置いておく。' EndOfLoop: Next i For i = 1 To 10 For j = 1 To 10 'ループの外へジャンプすることで、多重ループを抜ける。 If i = 5 And j = 5 Then GoTo EndOfLoop Next j Next i 'ループの外にラベルを置いておく。' EndOfLoop:
GoTo
はその名の通りgoto文であるため、上記のような慣例以外ではむやみに使わない方がよい。
配列
配列は、型名と最大の要素番号または要素番号の範囲を指定して以下のように宣言する。使用可能な要素番号はLBound
とUBound
で取得できる。
'hoge(0)~hoge(3)の4要素を持つ配列を宣言 Dim hoge(3) As Integer hoge(0) = 100 MsgBox LBound(hoge) & "~" & UBound(hoge) ' 0~3 'fuga(1)~fuga(3)の3要素を持つ配列を宣言 Dim fuga(1 To 3) As Integer fuga(1) = 100 MsgBox LBound(fuga) & "~" & UBound(fuga) ' 1~3 'piyo(0, 0)~piyo(1, 2)の6要素を持つ2次元配列を宣言 Dim piyo(1, 2) As Integer piyo(1, 2) = 100 MsgBox LBound(piyo, 1) & "~" & UBound(piyo, 1) ' 0~1 MsgBox LBound(piyo, 2) & "~" & UBound(piyo, 2) ' 0~2
要素数を動的に決めるには、要素数未定で宣言した後、ReDim
を使う。
Dim hoge() As Integer ReDim hoge(3) 'hoge(0)~hoge(3)が使用可能となる。 hoge(3) = 100
配列の各要素を任意の値で初期化するのにArray
が使用できる。
'要素数未定のVariant型で宣言する。 Dim hoge() As Variant 'hoge(0)~hoge(4)の5つの要素を任意の値で初期化する。 hoge = Array(1, 2, 3, 4, 5)
連想配列
連想配列を実現するにはDictionary
を使用する。
'連想配列の作成 Dim hash As Object Set hash = CreateObject("Scripting.Dictionary") 'キー・値ペアの追加 hash.Add "key1", 100 hash.Add "key2", 200 '値の取得 MsgBox hash.Item("key1") '値の削除 hash.Remove "key2" '存在確認 If hash.Exists("key2") Then … End If '値の列挙 Dim key As Variant For Each key In hash MsgBox hash.Item(key) Next key
With文
同じオブジェクトに対して連続して処理を記述するような場合、With文が便利である。
'With文を使わない場合 Worksheets("Sheet1").Range("A1") = 100 Worksheets("Sheet1").Range("B2") = 200 Worksheets("Sheet1").Range("C3") = 300 'With文を使う場合 With Worksheets("Sheet1") .Range("A1") = 100 .Range("B2") = 200 .Range("C3") = 300 End With
With文は入れ子にもできるが、可読性が落ちる場合もあるため注意が必要である。また、With
~End With
の中で最初にWithで指定したオブジェクト自体に変化が及ぶような処理を行なってはいけない。
Excel上の操作
ワークブックの操作
現在開いているワークブックはWorkbooks
から取得する。Excelでは、通常同じファイル名のワークブックは同時に開くことができないため、開いているワークブックは下記のようにファイル名のみによって一意に特定できる。
'Workbook型の変数を宣言 Dim myWorkbook As Workbook 'ワークブック「myWorkbook.xlsx」を取得 Set myWorkbook = Workbooks("myWorkbook.xlsx")
現在開いている全てのワークブックを列挙するには、以下のようにする。これで目的のワークブックが開かれているか事前に確認した方がよい(オブジェクトが存在しない状態はIs Nothing
で判定できる)。
Dim wb As Workbook, wbName As String, wbTarget As Workbook '開いている全てのワークブックについてくり返し For Each wb In Workbooks 'Nameプロパティでワークブック名を取得 wbName = wb.Name '目的のワークブックが見つかればくり返しを抜ける If wbName = "Book1.xlsx" Then Set wbTarget = wb Exit For End If Next 'ワークブックが見つからなかったら終了する If wbTarget Is Nothing Then MsgBox "ワークブックが開かれていません。" Exit Sub End If
現在最前面で開いているワークブックはActiveWorkbook
、実行しているマクロが保存されているワークブックはThisWorkbook
で取得できる。マクロが保存されているワークブックとは異なるワークブックを処理対象とすることもあるため、ActiveWorkbook
とThisWorkbook
は常に同じとは限らない。
Dim name As String '自分自身のワークブック名 name = ThisWorkbook.Name
ワークシートの操作
ワークシートは、WorkbookオブジェクトのWorksheets
プロパティから取得する。Worksheets
には、1から始まるインデックス番号か、ワークシート名を与えることで、特定のワークシートを取得できる。
'Worksheet型の変数を宣言 Dim myWorksheet As Worksheet 'myWorkbookの「Sheet1」というワークシートを取得 Set myWorksheet = myWorkbook.Worksheets("Sheet1")
ワークブック内のワークシートを列挙するには、以下のようにする。他のワークブックのワークシートを参照する場合などは、ワークブックの場合と同様にこちらも事前に存在確認をした方がよい。
Dim ws As Worksheet, wsName As String '全てのワークシートについてくり返し For Each ws In myWorkbook.Worksheets 'Nameプロパティでワークシート名を取得 wsName = ws.Name … Next
なお、ワークブックの指定を省略してWorksheets
とだけ書いた場合は、ThisWorkbook.Worksheets
と同じ意味になるため、マクロを保存したワークブック内で処理が完結するのであれば、ワークブックの指定は省略できる。
現在最前面に表示しているシートはActiveSheet
で取得できる。当然ながら、これはActiveWorkbook.ActiveSheet
の略である。
セルの操作
ワークブック、ワークシートを特定して、初めてセルの操作が可能となる。単一セルまたはセル範囲を表すオブジェクトはRange
オブジェクトといい、Worksheet
オブジェクトのRange
またはCells
プロパティによって取得する。ワークシートの指定を省略した場合、ActiveSheet
を指定したものとなる。
Range
とCells
の使い分け方としては、基本的に、変数を使って動的に位置を指定する場合にCells
を使う。"A2"
などの文字列を生成してRange
に渡すことも不可能ではないが、コードの可読性に難が生じるため通常は行わない。
Cells(2, 1)
は実際にはCells.Item(2, 1)
の省略形である。後述の例で分かるように、引数の無いCells
は全てのセルを表し、Item
でその範囲内の相対位置を指定することで、単一のセルを取得している。
'A2セル Range("A2") Cells(2, 1) Range(Cells(2, 1)) 'A2セルとB4セル Range("A2,B4") 'A2~B4の矩形範囲 Range("A2:B4") Range("A2", "B4") Range(Cells(2, 1), "B4") Range(Cells(2, 1), Cells(4, 2))
行や列の全体を選択するには、Range
でも可能なほか、Rows
やColumns
も使用できる。また、前述の通り、引数無しのCells
は全セルを表す。
'2~4行の全て Range("2:4") Range(Rows(2), Rows(4)) Rows("2:4") 'A~B列の全て Range("A:B") Range(Columns(1), Columns(2)) Columns("A:B") '全てのセル Cells
あるセルからの相対的な位置を選択するには、Offset
を使用する。また、Ctrlキー+矢印キーを押したときのように連続したデータの端のセルを選択するのにEnd
が使用できる。さらに、範囲内の1つのセルを選択するには、Cells
が暗黙的に使用しているItem
をRange
オブジェクトに対して使用すればよい。
'A2セルから2行下1列右のセル(=B4セル) Range("A2").Offset(2, 1) 'A1セルから見て下方向または右方向に連続したデータの端のセル Range("A1").End(xlDown) Range("A1").End(xlToRight) '選択したセル範囲内の各セルについてくり返し Dim myCell As Range, i As Integer Set myCell = Range("A3:A7") For i = 1 To 5 'A3~A7が順に選択される MsgBox myCell.Item(i, 1) Next i
Range
オブジェクトが取得できたら、そのセルに対して各種の操作が可能となる。値の代入や取得の際の.Vaule
は省略できる。
'値の取得 Dim val As String val = Range("A2").Value val = Cells(2, 1).Value 'セルへ値の代入 Range("A2").Value = 1234 Cells(2, 1).Value = 1234 'セル位置の取得 Dim i As Integer, j As Integer i = Range("A2").Row ' 2 j = Range("A2").Column ' 1 '範囲内に含まれるセルの数 MsgBox Range("A2:B4").Count ' 6 '範囲内で指定の文字列に一致するセル MsgBox Range("1:1").Find("価格").Column
セルの書式や装飾
セルの文字色や背景色は以下のようにして設定できる。パレット番号は、「カラーパレットの位置」を表す番号で、全部で56種類あり、デフォルトでは以下のようになっている。ユーザーによってパレットが変更されている場合は異なる色になっていることもある。
'RGBで指定 Range("A1").Font.Color = RGB(0, 0, 0) '文字色 Range("A1").Interior.Color = RGB(255, 255, 255) '背景色 'パレット番号で指定 Range("A1").Font.ColorIndex = 1 '文字色 Range("A1").Interior.ColorIndex = 2 '背景色
パレット番号とデフォルトの色: 1 53 52 51 49 11 55 56 9 46 12 10 14 5 47 16 3 45 43 50 42 41 13 48 7 44 6 4 8 33 54 15 38 40 36 35 34 37 39 2 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
フォントと文字サイズは以下のようにして設定できる。
Range("A1").Font.Name = "MS Pゴシック" Range("A1").Font.Size = 14
行の高さや列の幅は以下のようにして設定できる。
Rows(1).RowHeight = 20 '1行の高さ Columns(1).ColumnWidth = 20 'A列の幅
文字の位置は以下のようにして設定できる。
Range("A1").HorizontalAlignment = xlLeft '左揃え Range("A1").HorizontalAlignment = xlCenter '中央揃え Range("A1").HorizontalAlignment = xlRight '右揃え Range("A1").VerticalAlignment = xlTop '上揃え' Range("A1").VerticalAlignment = xlCenter '上下中央揃え' Range("A1").VerticalAlignment = xlBottom '下揃え'
その他、様々な設定が自在にできる。
メッセージボックス
画面に確認ダイアログを出すにはMsgBox
を使う。
'「完了しました。」というメッセージと「OK」ボタンを備えたダイアログを表示。 MsgBox "完了しました。"
第2引数で、表示するボタンの種類やダイアログのアイコンを変更できる。
'警告アイコンのダイアログを表示。 MsgBox "この操作はできません。", vbCritical
()
を記述して実行すると、ユーザーが押したボタンを戻り値として受け取ることができる。
'戻り値を受け取るための変数 Dim ans As Integer '「OK」「キャンセル」の2つのボタンと問い合わせアイコンを表示する。 ans = MsgBox("実行してよろしいですか?", vbOKCancel + vbQuestion) '押されたボタンによって条件分岐などができる。 If ans = vbCancel Then Exit Sub
表示するボタンの種類やダイアログのアイコンを指定する定数は以下のようなものがある。ボタンとアイコンを同時に指定するには、上記例のようにそれぞれを足し合わせて指定すればよい。
定数 | 意味 |
---|---|
| 「OK」ボタンのみ表示 |
| 「OK」ボタンと「キャンセル」ボタンを表示 |
| 「中止」「再試行」「無視」の3ボタンを表示 |
| 「はい」「いいえ」「キャンセル」の3ボタンを表示 |
| 「はい」ボタンと「いいえ」ボタンを表示 |
| 「再試行」ボタンと「キャンセル」ボタンを表示 |
| 警告アイコンを表示 |
| 問い合わせアイコンを表示 |
| 注意アイコンを表示 |
| 情報アイコンを表示 |
また、戻り値として受け取る値は以下のようなものがある。
定数 | 意味 |
---|---|
| 「OK」ボタンが押された。 |
| 「キャンセル」ボタンが押された。 |
| 「中止」ボタンが押された。 |
| 「再試行」ボタンが押された。 |
| 「無視」ボタンが押された。 |
| 「はい」ボタンが押された。 |
| 「いいえ」ボタンが押された。 |
MsgBox
の第3引数には、ダイアログウインドウのタイトルを指定できる。省略するとタイトル部分は「Microsoft Excel」と表示される。
その他
ボタンによるマクロ実行
ワンクリックでマクロ(Subプロシージャ)を実行できるボタンをワークシート上に作成するには、開発タブの「挿入」>「ボタン(フォームコントロール)」を選択する。ワークシート上でドラッグするとボタンが生成されて、クリック時に実行するマクロを選択できる。
作成後のボタンは、クリックするとマクロが即実行されてしまうため、リサイズや移動をしたりボタン名を変更したりするには、Ctrl+クリックをする。
省略記法
ここまで見てきた通り、VBAでは様々な省略記法があり、省略する方が一般的となっているものも多いが、省略しない記法を知ることで理解が深まる場合もある。
以下の外部リンクが詳しい。
ファイル出力
テキストファイルの出力は以下のようにする。出力先のファイル名はフルパスで指定する必要がある。ワークブックのあるディレクトリのパスを得るにはPath
を参照すればよい。
Dim fileName As String fileName = ThisWorkbook.Path & "\output.txt" Open fileName For Output As #1 Print #1, "出力テスト" & vbLf; Close #1
Print
は通常自動的に改行を出力するが、上記のように末尾に;
を付けると改行を出力しない。改行文字を指定したい場合や、1行を複数に分けて出力するときなどは;
をつける必要がある。
BOMなしUTF-8でのファイル出力
VBAにおいて、テキストファイルへの出力をすると、通常の方法では文字コードがShift_JISやBOMありのUTF-8となってしまう。BOMなしのUTF-8で出力するには、以下のような極めて回りくどい方法が必要となる。
Dim outputText As String, fileName As String '出力するテキスト oututText = "出力する文字列" '出力するファイル名 fileName = "C:\~\output.txt" Dim fout As Object, bytes() As Byte Set fout = CreateObject("ADODB.Stream") With fout .Type = adTypeText .Charset = "UTF-8" .Open .WriteText outputText .Position = 0 .Type = adTypeBinary .Position = 3 bytes = .Read .Position = 0 .Write bytes .SetEOS .SaveToFile fileName, adSaveCreateOverWrite .Close End With
やっていることは、「UTF-8に出力後、バイナリに変換し、先頭3バイト(BOM)を削る」ということのようである。なお、途中で登場するad~
から始まる定数を使用するには、VBEのメニューの「ツール」>「参照設定」から「Microsoft ActiveX Data Objects~」を選択しておく必要がある。