すべてにご挨拶。
この投稿では、さまざまなルーチンを自動化するために、VBAとは何か、Microsoft Excel 2007/2010でVBAを使用する方法(古いバージョンの場合、インターフェイスのみが変更され、コードはほとんど同じになる)を説明します。
      VBA(Visual Basic for Applications)は、多くのMicrosoft Office製品に組み込まれているVisual Basicの簡易バージョンです。 特定のドキュメントのファイルにプログラムを直接書くことができます。 さまざまなIDEをインストールする必要はありません-デバッガーを含むすべてが既にExcelにあります。
Visual Studio Tools for Officeを使用して、C#でマクロを記述し、それらを埋め込むこともできます。 FireStormに感謝します 。
私はすぐに言わなければならない-他の言語(C ++ / Delphi / PHP)での書き込みも可能ですが、オフィスファイルの読み取り、変更、書き込みの方法を学ぶ必要があります-ドキュメントに埋め込むことはできません。 また、MicrosoftインターフェイスはCOMを介して機能します。 すべての恐怖を理解するために、COMを使用したHello Worldを紹介します。
したがって、悲しいかな、Visual Basicを学習します。
少しの準備と問題の説明
行きましょう。 Excelを開きます。
まず、開発者パネルをリボンに追加しましょう。 フォームを構築するためのボタン、テキストフィールド、その他の要素が含まれています。


タブが表示されました。

ここで、VBAを研究する例について考えてみましょう。 最近、表のように見える価格表をうまく整理する必要がありました。 Googleにアクセスし、「価格表」を入力して、次のように装飾されたものをダウンロードします(広告の場合は考慮しないでください)。

つまり、商品を組み合わせることができる少なくとも2つのグループが必要です(この場合、これらはこの順序でタイプとメーカーになります)。 提案したアルゴリズムが正しく機能するように、1つのグループの商品が最初に並んでいるように商品を並べ替えます(最初にType 、次にManufacturer )。
達成したい結果は次のようになります。

もちろん、コンピューターでのみ価格表を見る場合は、フィルターを追加できます。適切な製品を検索する方がはるかに便利です。 ただし、コーディング方法を学びたいので、タスクは非常に適切です。
コディム
最初にボタンを作成する必要があります。クリックすると、プログラムが呼び出されます。 ボタンは「開発者」パネルにあり、「挿入」ボタンに表示されます。 ボタンフォームコンポーネントが必要です。 クリックして、シートの任意の場所に置きます。 さらに、マクロ宛先ウィンドウが表示されない場合は、右クリックして「マクロの割り当て」項目を選択する必要があります。 FormatPriceと呼びましょう。 マクロ名の前に何もないことが重要です。そうしないと、ブックの名前空間ではなく、別のモジュールで作成されます。 この場合、選択したシートにすばやくアクセスすることはできません。 「新規」ボタンをクリックします。


そして、ここではVB開発環境にいます。 また、コンテキストメニューから「ソーステキスト」/「コードの表示」コマンドを使用して呼び出すこともできます。
スタブプロシージャのあるウィンドウを次に示します。 デプロイできます。 コードは次のようになります。
Sub FormatPrice() 
      
      
      
        
        
        
      
     
      
        
        
        
      
     End Sub
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
Hello Worldを書きましょう。
 Sub FormatPrice() 
      
      
      
        
        
        
      
     MsgBox "Hello World!" 
      
        
        
        
      
     End Sub
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
そして、ボタンをクリックする(以前に選択を削除する)か、エディターから直接F5を押すことで開始します。
ここでは、おそらく、VBの構文に関する小さな教育プログラムに気を取られるはずです。 誰が知っているか、彼はこのセクションを最後まで安全にスキップできる。 Visual BasicとPascal / C / Javaの主な違いは、コマンドが分離されていないことです。 ただし、実際に1行に複数のコマンドを記述したい場合は、改行またはコロン( :)を使用します。 構文の基本的なルールを理解するために、抽象的なコードを提供します。
構文例
' .    
      
        
        
        
      
     '   VBA  
      
        
        
        
      
     Sub foo(a As String , b As String ) 
      
        
        
        
      
     ' Exit Sub '   "  " 
      
        
        
        
      
     MsgBox a + ";" + b 
      
        
        
        
      
     End Sub 
      
        
        
        
      
     
      
        
        
        
      
     ' .  Integer 
      
        
        
        
      
     Function LengthSqr(x As Integer , y As Integer ) As Integer 
      
        
        
        
      
     ' Exit Function 
      
        
        
        
      
     LengthSqr = x * x + y * y 
      
        
        
        
      
     End Function 
      
        
        
        
      
     
      
        
        
        
      
     Sub FormatPrice() 
      
        
        
        
      
     Dim s1 As String , s2 As String 
      
        
        
        
      
     s1 = "str1" 
      
        
        
        
      
     s2 = "str2" 
      
        
        
        
      
     If s1 <> s2 Then 
      
        
        
        
      
     foo "123" , "456" '      
      
        
        
        
      
     End If 
      
        
        
        
      
     
      
        
        
        
      
     Dim res As sTRING '   VB  . ,    
      
        
        
        
      
     Dim i As Integer 
      
        
        
        
      
     '       
      
        
        
        
      
     For i = 1 To 10 
      
        
        
        
      
     res = res + CStr(i) '     String 
      
        
        
        
      
     If i = 5 Then Exit For 
      
        
        
        
      
     Next i 
      
        
        
        
      
     
      
        
        
        
      
     Dim x As Double 
      
        
        
        
      
     x = Val( "1.234" ) '   
      
        
        
        
      
     x = x + 10 
      
        
        
        
      
     MsgBox x 
      
        
        
        
      
     
      
        
        
        
      
     On Error Resume Next '   -    
      
        
        
        
      
     x = 5 / 0 
      
        
        
        
      
     MsgBox x 
      
        
        
        
      
     
      
        
        
        
      
     On Error GoTo Err '      Err 
      
        
        
        
      
     x = 5 / 0 
      
        
        
        
      
     MsgBox "OK!" 
      
        
        
        
      
     GoTo ne 
      
        
        
        
      
     
      
        
        
        
      
     Err: 
      
        
        
        
      
     MsgBox "Err!" 
      
        
        
        
      
     
      
        
        
        
      
     ne: 
      
        
        
        
      
     On Error GoTo 0 '    
      
        
        
        
      
     
      
        
        
        
      
     '  ,   
      
        
        
        
      
     Do While True 
      
        
        
        
      
     Exit Do 
      
        
        
        
      
     
      
        
        
        
      
     Loop 'While True 
      
        
        
        
      
     Do 'Until False 
      
        
        
        
      
     Exit Do 
      
        
        
        
      
     Loop Until False 
      
        
        
        
      
     '     ,     ,  . 
      
        
        
        
      
     ' Val    Integer 
      
        
        
        
      
     Select Case LengthSqr(Len( "abc" ), Val( "4" )) 
      
        
        
        
      
     Case 24 
      
        
        
        
      
     MsgBox "0" 
      
        
        
        
      
     Case 25 
      
        
        
        
      
     MsgBox "1" 
      
        
        
        
      
     Case 26 
      
        
        
        
      
     MsgBox "2" 
      
        
        
        
      
     End Select 
      
        
        
        
      
     
      
        
        
        
      
     '  . 
      
        
        
        
      
     '      ReDim (Preserve) - . google 
      
        
        
        
      
     Dim arr(1 to 10, 5 to 6) As Integer 
      
        
        
        
      
     arr(1, 6) = 8 
      
        
        
        
      
     
      
        
        
        
      
     Dim coll As New Collection 
      
        
        
        
      
     Dim coll2 As Collection 
      
        
        
        
      
     coll.Add "item" , "key" 
      
        
        
        
      
     Set coll2 = coll '       Set 
      
        
        
        
      
     MsgBox coll2( "key" ) 
      
        
        
        
      
     Set coll2 = New Collection 
      
        
        
        
      
     MsgBox coll2.Count 
      
        
        
        
      
     End Sub
      
      熊手-1。 IDEからコードを(英語のExcelで)コピーすると、すべてのテキストが1252 Latin-1に変換されます。 したがって、ロシア語のコメントを保存する場合は、ワニをLatin-1として保存し、1251で開く必要があります。
レーキ2。 なぜなら VBでは未宣言の変数を使用できます。OptionExplicitは常にコードの先頭(すべての手順の前)に配置します。 このディレクティブは、インタープリターがそれ自体で変数を開始するのを防ぎます。
すくい3。 グローバル変数は、最初の関数/プロシージャの前でのみ宣言できます。 ローカル-プロシージャ/ファンクション内の任意の場所。
InPos 、 Mid 、 Trim 、 LBound 、 UBoundといった便利な追加機能がいくつかあります。 また、関数の操作/そのパラメーターに関するすべての質問に対する回答は、MSDNで入手できます。
これで、コードを怖がらず、自分でコンピューターサイエンスの宿題を書くのに十分であることを願っています。 投稿中に、目立たないように新しいデザインを紹介します。
私たちはExcelの下でたくさんコーディングします
このパートでは、Excelのシートで機能するもののコーディングを既に開始します。 まず、 resultという名前の別のシートを作成します(データシートはdataと呼ばれます )。 さて、おそらく、このシートの内容をクリアする必要があります。 また、データシートを「選択」して、シートを使用して配列に長い呼び出しを書き込まないようにします。
 Sub FormatPrice() 
      
      
      
        
        
        
      
     Sheets( "result" ).Cells.Clear 
      
        
        
        
      
     Sheets( "data" ).Activate 
      
        
        
        
      
     End Sub
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
セル範囲を操作する
Excel VBAでのすべての作業は、セル範囲で行われます。 それらはRange関数によって作成され、タイプRangeのオブジェクトを返します。 彼はデータやデザインを扱うのに必要なすべてを持っています。 ところで、シートのCellsプロパティもRangeです。
範囲の例
Sheets( "result" ).Activate 
      
        
        
        
      
     Dim r As Range 
      
        
        
        
      
     Set r = Range( "A1" ) 
      
        
        
        
      
     r.Value = "123" 
      
        
        
        
      
     Set r = Range( "A3,A5" ) 
      
        
        
        
      
     r.Font.Color = vbRed 
      
        
        
        
      
     r.Value = "456" 
      
        
        
        
      
     Set r = Range( "A6:A7" ) 
      
        
        
        
      
     r.Value = "=A1+A3"
      
      それでは、コードのアルゴリズムを理解しましょう。 したがって、2番目から始まるデータシートの各行には、興味のないデータ( ID 、 名前 、および価格 )があり、それが属する2つのネストされたグループ( typeおよびmanufacturer )があります。 さらに、これらの行はソートされます。 新しいグループを始める前にギャップを忘れてしまいますが、それは簡単です。 私はこのようなアルゴリズムを提案します:
- 次の行からグループをカウントしました。
 -  すべてのグループを優先度の高い順に並べます(最初の大きなグループ) 
      
- 現在のグループが一致しない場合、 AddGroup(i、name)プロシージャを呼び出します。ここで、 iはグループ番号(現在の番号から最大まで)、 nameはその名前です。 ヘッダーだけでなく、すべてのヘッダーを作成するには、いくつかの呼び出しが必要です。
 
 - 必要なヘッダーをすべて描画した後、別の行を作成してデータを入力します。
 
作業を簡素化するために、次の削減関数を定義することをお勧めします。
 Function GetCol(Col As Integer ) As String 
      
      
      
        
        
        
      
     GetCol = Chr(Asc( "A" ) + Col) 
      
        
        
        
      
     End Function 
      
        
        
        
      
     
      
        
        
        
      
     Function GetCellS(Sheet As String , Col As Integer , Row As Integer ) As Range 
      
        
        
        
      
     Set GetCellS = Sheets(Sheet).Range(GetCol(Col) + CStr(Row)) 
      
        
        
        
      
     End Function 
      
        
        
        
      
     
      
        
        
        
      
     Function GetCell(Col As Integer , Row As Integer ) As Range 
      
        
        
        
      
     Set GetCell = Range(GetCol(Col) + CStr(Row)) 
      
        
        
        
      
     End Function
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
次に、グローバル変数「現在の行」を定義します: Dim CurRow As Integer 。 手順の始めに、それは統一に等しくする必要があります。 また、変数「 データの現在の行」、現在の前の行のグループ名を持つ配列が必要です。 次に、「行の最初のセルが空でない間に」サイクルを書くことができます。
グローバル変数
Option Explicit '       
      
        
        
        
      
     Dim CurRow As Integer 
      
        
        
        
      
     Const GroupsCount As Integer = 2 
      
        
        
        
      
     Const DataCount As Integer = 3
      
      フォーマット価格
Sub FormatPrice() 
      
        
        
        
      
     Dim I As Integer '   data 
      
        
        
        
      
     CurRow = 1 
      
        
        
        
      
     Dim Groups(1 To GroupsCount) As String 
      
        
        
        
      
     Dim PrGroups(1 To GroupsCount) As String 
      
        
        
        
      
     
      
        
        
        
      
     Sheets( "data" ).Activate 
      
        
        
        
      
     I = 2 
      
        
        
        
      
     Do While True 
      
        
        
        
      
     If GetCell(0, I).Value = "" Then Exit Do 
      
        
        
        
      
     ' ... 
      
        
        
        
      
     I = I + 1 
      
        
        
        
      
     Loop 
      
        
        
        
      
     End Sub
      
      次に、 グループ配列にデータを入力する必要があります 。
省略記号の代わりに
Dim I2 As Integer 
      
        
        
        
      
     For I2 = 1 To GroupsCount 
      
        
        
        
      
     Groups(I2) = GetCell(I2, I) 
      
        
        
        
      
     Next I2 
      
        
        
        
      
     ' ... 
      
        
        
        
      
     For I2 = 1 To GroupsCount ' VB     
      
        
        
        
      
     PrGroups(I2) = Groups(I2) 
      
        
        
        
      
     Next I2 
      
        
        
        
      
     I =  I + 1
      
      そしてヘッダーを作成します:
前の部分の省略記号の代わりに
For I2 = 1 To GroupsCount 
      
        
        
        
      
     If Groups(I2) <> PrGroups(I2) Then 
      
        
        
        
      
     Dim I3 As Integer 
      
        
        
        
      
     For I3 = I2 To GroupsCount 
      
        
        
        
      
     AddHeader I3, Groups(I3) 
      
        
        
        
      
     Next I3 
      
        
        
        
      
     Exit For 
      
        
        
        
      
     End If 
      
        
        
        
      
     Next I2
      
      AddHeaderプロシージャを忘れないでください。
フォーマット前価格
Sub AddHeader(Ty As Integer , Name As String ) 
      
        
        
        
      
     GetCellS( "result" , 1, CurRow).Value = Name 
      
        
        
        
      
     CurRow = CurRow + 1 
      
        
        
        
      
     End Sub
      
      次に、すべての情報を結果に転送する必要があります
 For I2 = 0 To DataCount - 1 
      
      
      
        
        
        
      
     GetCellS( "result" , I2, CurRow).Value = GetCell(I2, I) 
      
        
        
        
      
     Next I2
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
列を幅に合わせ、 結果シートを選択して結果を表示します
FormatPriceの最後のループの後
Sheets( "Result" ).Activate 
      
        
        
        
      
     Columns.AutoFit
      
      それだけです 最初のバージョンを楽しむことができます。

glyいですが、それはそうです。 フォーマットを処理しましょう。 まず、 AddHeaderプロシージャを変更します。
 Sub AddHeader(Ty As Integer , Name As String ) 
      
      
      
        
        
        
      
     Sheets( "result" ).Range( "A" + CStr(CurRow) + ":C" + CStr(CurRow)).Merge 
      
        
        
        
      
     '            
      
        
        
        
      
     '    With 
      
        
        
        
      
     With GetCellS( "result" , 0, CurRow) 
      
        
        
        
      
     .Value = Name 
      
        
        
        
      
     .Font.Italic = True 
      
        
        
        
      
     .Font.Name = "Cambria" 
      
        
        
        
      
     Select Case Ty 
      
        
        
        
      
     Case 1 '  
      
        
        
        
      
     .Font.Bold = True 
      
        
        
        
      
     .Font.Size = 16 
      
        
        
        
      
     Case 2 '  
      
        
        
        
      
     .Font.Size = 12 
      
        
        
        
      
     End Select 
      
        
        
        
      
     .HorizontalAlignment = xlCenter 
      
        
        
        
      
     End With 
      
        
        
        
      
     CurRow = CurRow + 1 
      
        
        
        
      
     End Sub
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     
すでに良い:

境界を描くためだけに残っています。 ここでは、すでにすべての結合されたセルを操作する必要があります。そうでない場合は、1つだけが境界線を持ちます。

したがって、境界線スタイルを追加してコードをわずかに変更します。
 Sub AddHeader(Ty As Integer , Name As String ) 
      
      
      
        
        
        
      
     With Sheets( "result" ).Range( "A" + CStr(CurRow) + ":C" + CStr(CurRow)) 
      
        
        
        
      
     .Merge 
      
        
        
        
      
     .Value = Name 
      
        
        
        
      
     .Font.Italic = True 
      
        
        
        
      
     .Font.Name = "Cambria" 
      
        
        
        
      
     .HorizontalAlignment = xlCenter 
      
        
        
        
      
     
      
        
        
        
      
     Select Case Ty 
      
        
        
        
      
     Case 1 '  
      
        
        
        
      
     .Font.Bold = True 
      
        
        
        
      
     .Font.Size = 16 
      
        
        
        
      
     .Borders(xlTop).Weight = xlThick 
      
        
        
        
      
     Case 2 '  
      
        
        
        
      
     .Font.Size = 12 
      
        
        
        
      
     .Borders(xlTop).Weight = xlMedium 
      
        
        
        
      
     End Select 
      
        
        
        
      
     .Borders(xlBottom).Weight = xlMedium '  : xlThick, xlMedium, xlThin, xlHairline 
      
        
        
        
      
     End With 
      
        
        
        
      
     CurRow = CurRow + 1 
      
        
        
        
      
     End Sub
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     

新しいグループを開始する前にパスを達成するためだけに残ります。 これは簡単です:
FormatPriceの開始時
Dim I As Integer '    data 
      
        
        
        
      
     CurRow = 0 '        
      
        
        
        
      
     Dim Groups(1 To GroupsCount) As String
      
      見出しループで
If Groups(I2) <> PrGroups(I2) Then 
      
        
        
        
      
     CurRow = CurRow + 1 
      
        
        
        
      
     Dim I3 As Integer
      
      
まさに彼らが望んだもの。
 この記事が、VBAのExcelプログラミングに少し慣れるのに役立つことを願っています。 宿題-見出し「 ID、タイトル、価格 」を結果に追加します。 ヒント: CurRow = 0 CurRow = 1 
 ファイルはここ (min.us)またはここ (Dropbox) からダウンロードできます。 マクロの実行を有効にしてください。  誰かが人間のファイルホスティングを促す場合は、そこにアップロードします。 
ご清聴ありがとうございました。
コメントで建設的な批判ができればうれしいです。
UPD: Dropboxとmin.usでサンプルをリロードしました。
UPD2:実際には、 1つのパラメーターを使用してプロシージャを呼び出すときに、括弧を付けることができます。 または、 Call Fooコンストラクト(「bar」、1、2、3)を使用します -ここでは、ブラケットが常に必要です。
 