ExcelVBA Microsoft

ExcelVBAの基本まとめ

セルの操作

セルの入力

Sub celltest()
    '文字の代入
    Range("A1").Value = "let's test"
    
    '数式の代入
    Range("A2").Value = "=1+1"
End Sub

セルのコピー

Sub copytest()
    '[コピー元セル].copy [貼り付け先セル]
    Range("A1").Copy Sheet2.Range("A1")
    '注意点:書式などもコピーされる
    
    '値だけをコピーしたいなら代入する
    '変数の代入と同じ形になる(.copyとは左右が逆転する)点に注意
    Sheet2.Range("A2").Value = Range("A1").Value
    
    '表示形式だけコピー(実際やることは代入)
    Range("C4").NumberFormatLocal = Range("A4").NumberFormatLocal
End Sub

セルの値を取得

Sub celltest2()
    'セルに「=1+1」という数式が入ってる場合
    Debug.Print Range("A2").Value   '結果:2
    Debug.Print Range("A2").Value2  '結果:2
    Debug.Print Range("A2").Formula '結果:=1+1
    
    'セルに日付「2022/3/24」が入ってる場合
    Debug.Print Range("A3").Value   '結果:2022/3/24
    Debug.Print Range("A3").Value2  '結果: 44644 ※シリアル値(先頭に半角スペース有)
    Debug.Print Range("A3").Formula '結果:44644 ※シリアル値
    
    'セルに参照「=A1」が入ってる場合
    Debug.Print Range("C3").Value   '結果:let's test
    Debug.Print Range("C3").Value2  '結果:let's test
    Debug.Print Range("C3").Formula '結果:=A1
End Sub

セルの表示形式

Sub celltest3()
    'セルの値「10000」→「\10,000」という表示にする
    Range("A4").NumberFormatLocal = "\#,###"
End Sub

セルのクリア

Sub cellclear()
    '書式はそのままで、値だけ消す
    Range("A1").ClearContents
    'この""の代入でも同じ結果になる
    Range("A1").Value = ""
    '範囲指定
    Range("A1:C3") = ""
    
    '書式ごと全消去する
    Range("A1").Clear
    '書式だけ消去する
    Range("A1").ClearFormats
End Sub

セルに枠線を引く

Sub celltest4()
    'すべての縦、横に細い線
    Range("A1:C4").Borders.LineStyle = xlContinuous
    
    '太い外枠
    Range("A1:C4").BorderAround Weight:=xlMedium
End Sub

列の横幅を調整する

Sub columnwidth()
    '自動調整
    Columns("A:C").AutoFit
    
    '1文字分スペースを追加
    Columns("A:A").columnwidth = Columns("A:A").columnwidth + 1
    
    '5文字分という指定(pxではない)
    Columns(3).columnwidth = 5
End Sub

変数のデータ型

データ型の名前を調べる:TypeName()

Dim strA As String: strA = "hello"
Debug.Print TypeName(strA) 'String
Debug.Print TypeName(1234) 'Integer

データ型の変換

公式:データ型変換関数

Dim strB As String: strB = "01223"
Debug.Print TypeName(strB) 'String
Debug.Print TypeName(CLng(strB)) 'Long

数値:Long型

大体-2G~2Gの間 数字はとりあえずLong型にしとけばOK
Integer型は-32k~32kの間しかなく、オーバーフローエラーになりやすい
Byte型は0~255まで

数値型かどうかチェックする:IsNumeric()

Debug.Print IsNumeric("hello") 'False
Debug.Print IsNumeric(1234) 'True

小数点がある場合Currency型が安全

Double型だと小数点の計算時に予期せぬ結果になる可能性あり

Dim numA As Currency: numA = 0.1 + 0.2
Dim numB As Double: numB = 0.1 + 0.2
Debug.Print 0.3 = numA 'True
Debug.Print 0.3 = numB 'False

文字:String型

数字をString型にする:Str()

Debug.Print TypeName(123) ' Integer
Debug.Print TypeName(Str(123))  'String

文字数のカウント:Len()

Dim strA As String
Dim strB As String
strA = "hello"
Debug.Print Len(strA) '5
Debug.Print Len(strB) '0

文字列に変数を埋め込む方法

Pythonならf"hello, {name}"みたいに書けるが、VBAではreplace関数を使うか、文字と変数をでつなげるしかない

Debug.Print "こんにちは。現在" & Now() & "です"
'こんにちは。現在2024/12/15 14:55:59です

Debug.Print Replace("こんにちは。現在now_です", "now_", Now())
'こんにちは。現在2024/12/15 14:55:59です

長文を書く方法:改行コード「vbCrLf」で行をつなげる

コード自体の改行は「_」で可能

' 各行を配列として用意
Dim arr: arr = Array( _
    "VBAを学習するメリット", _
    "1)業務の効率化・自動化:繰り返し作業や定型処理を自動化することで、手作業の時間を大幅に削減できる", _
    "2)生産性向上:大量データの処理スピードが劇的に向上する", _
    "3)柔軟なツール開発:自分やチームの要望に合わせて独自の機能やツールを構築できる", _
    "4)メンテナンス性向上:システム開発に頼らず自力で改修・メンテナンスが可能となる", _
    "5)キャリアアップへの貢献:業務改善提案やITリテラシー向上により、職場での評価にプラスとなる" _
)

' Join関数で配列の要素をvbCrLfで連結
MsgBox Join(arr, vbCrLf)

日付:Date型

#YYYY/MM/DD#と書くと自動的に日付型となる

Debug.Print #12/14/2024# '2024/12/14
Debug.Print TypeName(#12/15/2024#) 'Date

※年を末尾にする必要はない。「#2024/12/15#」と書くとエディタが勝手に「#12/15/2024#」に置き換えてしまうだけ

日付の表示形式を指定する:Format() ※String型になる

Debug.Print Format(Now(), "YY/MM/DD") '24/12/15
Debug.Print TypeName(Format(Now(), "YY/MM/DD")) 'String

日数の計算:DateDiff()

第1引数に単位、第2引数と第3引数に日付を渡す
単位は日ならd、月ならm、年ならyyyyなど決まっている(公式ドキュメント参照)

Dim diff As Long: diff = DateDiff("d", Now(), #1/1/2025#)

Debug.Print Replace("お正月まであとdiff日", "diff", diff)
'お正月まであと17日

曜日の判定:Weekday(), WeekdayName()

Weekday()に日付を渡すと曜日番号を返し、
WeekdayName()に番号を渡すと曜日名を返す

Debug.Print Weekday(Now()) '1

Debug.Print WeekdayName(1) '日曜日
Debug.Print WeekdayName(2) '月曜日

条件分岐

If 文

ある条件の時はこうする、という感じで処理を分岐する超重要構文
ElseIf で2つ目以降も条件を追加できる
Elseでどの条件にも当てはまらなった場合の処理を書く(省略可)

Dim level As Long: level = 50

If level < 10 Then
    Debug.Print "Lv10になるまでスライムを倒そう"
ElseIf level < 50 Then
    Debug.Print "Lv50になるまで洞窟で修行しよう"
Else
    Debug.Print "そろそろ魔王をぶっ倒しに行こう!"
End If

Select Case 文

与えられた変数に対して、いろいろなパターン分けができる構文。ElseIfを大量に書くのが面倒な場合に使える

Dim Number: Number = 8

Select Case Number
    Case 1 To 5
        Debug.Print "Between 1 and 5"
   
    Case 6, 7, 8
        Debug.Print "Between 6 and 8"
        
    Case 9 To 10
        Debug.Print "Greater than 8"
        
    Case Else
        Debug.Print "Not between 1 and 10"
        
End Select

実行しますか?はい/いいえの確認ダイアログ

Dim res As Long
res = MsgBox("本当に実行しますか?", vbYesNo, "確認")

If res = vbYes Then
    Debug.Print "実行しました"
Else
    Debug.Print "キャンセルしました"
End If

ループ処理

For Next

自分で回数を指定して処理を繰り返す方法。1から順番に処理したい場合はこれを使う

Dim i As Long
For i = 1 To 10
    Cells(1, i).Value = "hello " & i
Next i

For Each

回数を指定せずにすべての要素を巡回する方法
全部の要素を調べるけど順番は重要じゃない、という場合によく使われる
例えばワークシートを1個ずつ調べて、ある条件に一致したら名前を変更したり削除したりする、といった処理

Dim ws As Worksheet
' 現在のブックに含まれる各ワークシートを巡回
For Each ws In ThisWorkbook.Worksheets
    Debug.Print ws.Name
Next ws

Do Loop

終了条件を満たすまで無限にループするタイプ。ゲームプログラミングでよく使われる

Dim userValue As Variant

Do
    ' ユーザーに数値の入力を求める
    userValue = InputBox("1~20の間で好きな数字を入力してください。(正解は10です)")
    
    ' キャンセルが押された場合はループを終了
    If userValue = False Then
        Exit Do
    End If

    ' 入力が正解かどうか判定
    If IsNumeric(userValue) Then
        If CInt(userValue) = 10 Then
            MsgBox "正解です!"
            Exit Do   ' 条件が満たされたのでループを抜ける
        Else
            MsgBox "不正解。もう一度入力してください。"
        End If
    Else
        MsgBox "数値を入力してください。"
    End If
Loop

処理の中断やスキップの方法

途中で処理を終了

  • For NextとFor Eachは「Exit For」でループを終了できる
  • Do Loopは「Exit Do」でループを終了できる

特定の場合に処理をスキップ

Pythonならcontinueという構文で処理をスキップできるが、VBAはcontinueに相当するものが無いので、if文で何もしない分岐を作るか、GoToで次のループに移行する方法がある。どちらを選ぶかは好みの問題

何もしないif文を作る例

Dim i As Long
For i = 1 To 10
    ' 特定条件を満たす場合は後続処理を飛ばしたい
    If i = 5 Then
        ' continue相当:何も実行せずにNext iへ
    Else
        ' 条件を満たさない場合は通常処理
        Cells(1, i).Value = "hello " & i
    End If
Next i

GoToでスキップする例 ※長い・複雑なコードでGoToを使うと、どこに飛ぶかわからなくて嫌われるので注意

Sub test()
    Dim i As Long
    For i = 1 To 10
        ' 特定条件を満たす場合は後続処理を飛ばしたい
        If i = 5 Then GoTo nextLoop
    
        Cells(1, i).Value = "hello " & i
nextLoop:
    Next i
End Sub

結果はどちらも同じ

エラーが発生した場合の処理

エラーを無視して次の処理に進む:Resume Next

Dim x As Long, y As Long
x = 1

On Error Resume Next

Debug.Print x / y

Debug.Print x, y ' 1          0

特定のラベルに飛ばす:GoTo ラベル名

エラー処理のラベルを書くときは必ず「Exit Sub」を書くようにする
エラーが起きなかったらExit Subで処理終了、
エラーが起きたらラベルに飛ぶ、という意味になる
「Exit Sub」を書き忘れると、エラーが起きなかった場合もエラーラベルの内容を実行してしまう

Sub test()

    Dim x As Long, y As Long
    x = 1
    
    On Error GoTo ErrHandler

    Debug.Print x / y

    Exit Sub

ErrHandler:
    Debug.Print "エラー:" & Err.Description
    'エラー:0 で除算しました。
    
End Sub

ラベルから元の行に戻る:Resume

下記のコードではyが0なので8行目でエラーが発生し12行目に飛ぶ→13行目でyに5を代入する→14行目で8行目に戻る→今度は8行目でエラーが発生しないので、10行目に到達して処理が終了する
この場合で「Exit Sub」を書き忘れると永遠に14行目から1行前に戻り続ける無限ループになるので注意

Sub test()

    Dim x As Long, y As Long
    x = 1
    
    On Error GoTo errHandler
    
    Debug.Print x / y '0.2
    
    Exit Sub

errHandler:
    y = 5
    Resume
    
End Sub

-ExcelVBA, Microsoft