hex309’s diary

備忘録としてぼちぼちやります。VBAネタが多くなりそうです

VBAの仕様書

いつも、リンク先を検索することになるので、ここに書いておきます。

VBAの仕様書は以下からダウンロードできます。

 

[MS-VBAL]: VBA Language Specification

 

サイトも英語ですが、仕様書も英語です(当たり前か)。

更新も行われていて、最新版は、12/15/2016のものです(2017/3/26現在)。

Rangeオブジェクトと引数のカッコの話


先日、次のようなコードを見る機会が有りました。

Sub CopySample1()
    Range("A1").Copy (Cells(1, 2))
    Range("A2").Copy (Range("B2"))
End Sub

このコード、どちらもCopyメソッドの引数Destinationを指定しています。違いと言えば、貼り付け対象のセル(Rangeオブジェクト)をCellsプロパティで指定しているか、Rangeプロパティで指定しているかです。

このコードですが、「Range("A2").Copy (Range("B2"))」がエラーになります。

しかし、次のコードの場合、どちらもエラーにはなりません。

Sub CopySample2()
    Range("A1").Copy Cells(1, 2)
    Range("A2").Copy Range("B2")
End Sub

「CopySample1」プロシージャと「CopySample2」プロシージャの違いは、引数を「()」で囲んでいるかいないかです。

では、この「()」で囲んだことで何が起きているのか、次のコードで確認してみます。

Sub TypeNameTest()
    Debug.Print "Cells : " & TypeName((Cells(1, 1))), TypeName(Cells(1, 1))
    Debug.Print "Range : " & TypeName((Range("A1"))), TypeName(Range("A1"))
End Sub

TypeName関数は、引数に関する情報(主にデータ型)を返します。
実行結果は次のようになります。

Cells : Range Range
Range : Empty Range

TypeName関数の引数にCellsプロパティを使ったものとRangeプロパティを使ったものの2パターン。さらに、それぞれ引数そのものをカッコで囲んだものと囲まないものの2パターンです。
Cellsプロパティが両方とも「Range」を返しているのに対し、Rangeプロパティの方は、引数そのものをカッコで囲んだ方は「Empty」が返っています。
この「Empty」ですが、実はこのテストをする時にセルA1には何も入力されていません。何も入力されていないセルの値はEmptyなので、それが返っています。
念のため、セルA1に文字列を入力して、このコードを実行すると「String」が返りました。

ということは、「(Range("A1"))」と指定したときには、セルの値を評価している、ということになります。つまり「(Range("A1").Value)」ということですね。

となると、最初のコード(再掲します)で、「Range("A2").Copy (Range("B2"))」がエラーになったのも理解できます。

Sub CopySample1()
    Range("A1").Copy (Cells(1, 2))
    Range("A2").Copy (Range("B2"))
End Sub

「()」で囲んだことで、「Range("B2")」が、「Range("B2").Value」と解釈されたということです。となると、Copyメソッドの引数にはRangeオブジェクトを指定しなくてはなりませんから、エラーになるのも当然と言えます。
それに対して、「(Cells(1, 2))」の方は、「()」で囲んでもRangeオブジェクトを返していたので、エラーにはならなかった、ということです。

基数変換(n進数を10進数に変換)

10進数をn進数に変換するコードを紹介したので、今回は逆です。

以前、10進数をn進数に変換するコードはコチラです。

hex309.hatenablog.com
hex309.hatenablog.com

というわけで、コチラ。

'n進数を10進数に変換
Private Sub ConvertIntoDecimalTest()
    'ConvertIntoDecimalプロシージャに指定する引数は「変換する値」「変換する値の基数」
    Debug.Print ConvertIntoDecimal("309", 16)
End Sub

Private Function ConvertIntoDecimal(ByVal ConvertValue As String, ByVal Radix As Long) As Long
    Dim NumOfDigits As Long
    Dim temp As String
    Dim Answer As Long
    Dim i As Long
    
    temp = StrReverse(ConvertValue)
    NumOfDigits = Len(ConvertValue)
    
    For i = 1 To NumOfDigits
        Answer = Answer + GetDecimalNumber(Mid$(temp, i, 1)) * Radix ^ (i - 1)
    Next
    ConvertIntoDecimal = Answer
End Function

Private Function GetDecimalNumber(ByVal Digit As String) As Long
    Dim temp As Variant
    temp = Array("0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F")
    GetDecimalNumber = Application.Match(Digit, temp, 0) - 1
End Function

基数変換(ループバージョン)

基数変換のループバージョンです。
以前紹介した再帰バージョンはコチラ。
hex309.hatenablog.com


今回も16進数までの対応です。16進数の文字列への変換を行うGetHexStringプロシージャは、再帰バージョンと同じです。
まぁ、こっちのほうがシンプルですよね。

'基数変換(10進数をn進数に変換する)ループバージョン
Private Sub RadixConversionLoopTest()
    Debug.Print RadixConversionLoop(777, 16)
End Sub

Private Function RadixConversionLoop(ByVal num As Long, ByVal Radix As Long) As String
    Dim Quotient As Long
    Dim Remainder As Long
    Dim Answer As String
    Quotient = num
    Do
        Remainder = Quotient Mod Radix
        Quotient = Quotient \ Radix
        Answer = GetHexString(Remainder) & Answer
    Loop Until Quotient = 0
    RadixConversionLoop = Answer
End Function

Private Function GetHexString(ByVal num As Long) As String
    Dim temp As Variant
    temp = Array("0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F")
    GetHexString = temp(num)
End Function

VBAの書籍

今、我が家にあるVBA関連の本で、良かったものを紹介します。

中には入手困難なものも有りますが、そこはご勘弁を。

 

 まずは、井川さんの本から。

「裏ワザ」というか、マニアックなネタが多い書籍です。勉強になりました。

Excel VBA裏ワザ大辞典―作業効率大幅アップ!最新最強の144TIPS (インプレスの辞典)

Excel VBA裏ワザ大辞典―作業効率大幅アップ!最新最強の144TIPS (インプレスの辞典)

 

 

次も井川さんの書籍です。

 これは有名ですかね。現在(2017/3/20)時点では入手できないようですが、チャンスが有れば、一度は見て欲しい書籍です。ただ、文章はちょっと難解なところがあります(井川さんの書籍はその傾向があります)。

日本で、クラスモジュールについてある程度書かれた書籍はこれが初だった気がします(違ったらすみません)。

そこが知りたい!Excel VBAプロの技 Excel97/2000/2002/2003対応!

そこが知りたい!Excel VBAプロの技 Excel97/2000/2002/2003対応!

 

 

もう1つ、井川さん関連です。コチラは共著になっています。

 共著の分、上記2冊よりは読みやすくなっています(井川さんすみません)。

また、発売当時はここまできちんとVBAによるOffice連携を扱った書籍がなかった記憶があります。

 

さて、井川さんは以上で、その他の書籍です。

 次は、何と言ってもコレです。1,000ページ以上有ります。英語です。

全部なんてとてもじゃないけど読んでません。細かいことを調べたいときには助かります(でも、英語です)。

VBA Developer's Handbook

VBA Developer's Handbook

 

 

 次はコチラ。

プログラムは「スピード命」というわけでもないですから(というか、そんな単純な話ではない)、参考資料という感じでしょうか。

Excel VBA パフォーマンスレポート (Something U want)

Excel VBA パフォーマンスレポート (Something U want)

  • 作者: 坪崎誠司
  • 出版社/メーカー: 株式会社プレスティージ
  • 発売日: 2010/01/26
  • メディア: 単行本(ソフトカバー)
  • クリック: 3回
  • この商品を含むブログを見る
 

 

次も同じ坪崎さんの書籍です。

 モジュールをVBAで扱うのが「プロ」なのかはわかりませんが、そのへんにページを割いています。こちらも私の場合は資料です。

Excelプロフェッショナルエンジニアテクニック

Excelプロフェッショナルエンジニアテクニック

  • 作者: 坪崎誠司
  • 出版社/メーカー: 株式会社プレスティージ
  • 発売日: 2008/11/17
  • メディア: 単行本(ソフトカバー)
  • クリック: 11回
  • この商品を含むブログを見る
 

 

後は、VBAだけというわけじゃないんですけど、コチラですかね。

 以下は、第2版ですが、最初の100選の方も持っています。結構、参考になりました。

Excel Hacks 第2版― プロが教える究極のテクニック140選

Excel Hacks 第2版― プロが教える究極のテクニック140選

 

 

と、ここまできてAccessVBAの書籍が無いことに気づきました。持っていないわけじゃないんですが、どうしてもExcelVBAの書籍のほうがメインになりますね。

 

データベース関連で言えば、VBAじゃなくVB6.0ですが、コチラが勉強になりました(古いですね)。

当時は、なかなか理解できずに何度も読み直した記憶が有ります。 

Visual Basicによるビジネスアプリケーション開発―オブジェクト指向設計で作る3層C/Sアプリケーション (Programmer’s SELECTION)

Visual Basicによるビジネスアプリケーション開発―オブジェクト指向設計で作る3層C/Sアプリケーション (Programmer’s SELECTION)

 

 

こんなところですかね。

入門書が全然ないとか、有名な人の書籍がないとか、まぁ、ツッコミどころもあるとは思いますが、あくまで、私の手元の本でのお話なので。ご了承くださいませ。

アルゴリズムの本

実は、こんな本を買いました。

アルゴリズム大事典 (I・O BOOKS)

アルゴリズム大事典 (I・O BOOKS)

 

 サンプルのコードがVBAというところが珍しいですかね。

VBAのコード自体は、スペースの関係でしょう、Valueプロパティが省略されていたりしていますが、参考になることは間違いありません。

基数変換

今回は、基数変換です。10進数をn進数に変換します(16進数まで)。
普通にループで処理すればいいんですけど、あえて再帰で。

'基数変換(10進数をn進数に変換する)
Private Sub RadixConversionTest()
    Debug.Print RadixConversion(777, 16)
End Sub

Private Function RadixConversion(ByVal num As Long, ByVal Radix As Long) As String
    Dim Quotient As Long
    Dim Remainder As Long
    
    Remainder = num Mod Radix
    Quotient = num \ Radix
    If Quotient = 0 Then
        RadixConversion = GetHexString(Remainder)
    Else
        RadixConversion = RadixConversion(Quotient, Radix) & GetHexString(Remainder)
    End If
End Function

Private Function GetHexString(ByVal num As Long) As String
    Dim temp As Variant
    temp = Array("0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F")
    GetHexString = temp(num)
End Function

ループ処理バージョンは、今度アップします(まだ書いてない)