見出し画像

【スキマ学習】ガチ初心者と一緒に、Excelでnoteのタグ解析ができるツールを作ってみよう《5》

今回から本格的にコードの中身について考えていきます。少し難易度が上がりますが、お付き合い頂ければ幸いです。

Excelのデータを別のシートにコピペする作業って結構多いと思います。応用の幅がとても広い技術なので、是非自分のものにしてください!宜しくお願い致します。

・会社にいてもちょっとしたスキマ時間に実践できるよう、一回の分量をなるべく少なくしてお送りします。
・特別な準備は要りません。オフィスのPCにだいたい入ってるエクセルとGoogleクロームだけを使って作ります。記事も無料です。


前回の記事はこちら


今回の内容はこんな感じです↓

右から左に書き写すって

Sub 並び替えて表にする()

   必要な情報のみを抽出する

   どこまでが1記事なのか把握する

   情報を横一列に整列させる

   表に書き写す ←今回はここをやります!

End Sub

前回、ツールの全貌をざっくりと日本語で設計してみました。今回はその一番最後の手順、「データを表に書き写す」の部分を作っていきたいと思います。

右にあるものを左に書き写すという作業は、私の最も苦手とする作業の一つです。

幼い頃には、電子機器技術が発達したこの時代における書き取りの宿題というものの必要性について考えているうちに、夜になってしまったこともありました。

※漢字の書き取りにはどうやら「覚える」以外にも意味があるようですが。

私たちの日ごろの業務の中でも、未だにデータをちくちくコピペしなければならない場面は存在しますし、多くのビジネスパーソンがこの単純作業に苦しめられているようです。

今回はそんな日本社会の闇を払拭する、極めて基本的なコードを勉強します。これを誰もが身に着け、この国から単純なコピペ作業がなくなってくれれば嬉しいです。


データの構造を把握する

さて、前回noteの画面からコピーしてきたデータを、Excelに貼り付けたままになっていたと思います。とりあえずこの構造がどうなっているのか見てみましょう。

画像1

画面上部のヘッダー部分の文字情報まで取れてしまっていますが、今回は使わないので消してしまいましょう。


画像2

そこから続く数行も、検索したタグ名、関連タグや切り替えタブ、件数などの目で見て分かるデータなので、一旦自動化の対象から外します。シンプルに記事のデータだけに気を配ることにしました。


そこから下が取り扱いたいデータ、記事のリストになっています。今回はたまたま、のんさんという方の記事が一番上に来ていたので、この投稿をベースに考えてみましょう。

画像3

こんな形になっていますね。

投稿されたての記事ということもあって、まだスキがついていないようです。この方法だとスキ=0のデータが取れないことが分かりました。

ちなみに、ちょっと下の方にあるスキが付いている記事だとこんな感じに残っています。

コメント 2019-12-12 115640

まとめると、だいたいこんな感じの構造になっていることが分かりました。

コメント 2019-12-12 120650


機械にわかるよう細分化する

最終的にはこれらの文字列データを並べ替えた後、別のシートに転記する必要があります。

今回は転記する最後の手順だけに注目することにしていたと思うので、こんな感じで仮のデータシートを作ってみました。

コメント 2019-12-13 115517

今のうちに適当なシートを作って、このようにデータを入れておいてください。

これを別の表に書き写します。書き写すということは、パソコン的に言えばデータをコピーして、貼り付けるという作業をするということです。

「表に書き写す」

↓

「データをコピーし、別のシートに貼り付ける」

この作業を人間の言葉から、機械の詳細な手順に焼き直すとどうなるでしょうか。少し考えてみてください。

機械には可能な限り具体的に、「どこの」「何を」「どのように」「どうする」といったことをプログラムで伝えてあげる必要がありました。

一段ずつ具体的な言葉にしていくと分かりやすいと思いますので、ちょっとやってみますね。

このシートのデータをコピーする

別のシートにデータを貼り付ける

更に細かくしていきましょう。

このシートのデータをコピーする
    ・アクティブなシートの
    ・この範囲のセルの
    ・値にアクセスして
    ・すべてを記憶する
    

別のシートにデータを貼り付ける
    ・別なシートの
    ・この範囲のセルの
    ・値にアクセスして
    ・さっき記憶したデータを
    ・すべて記入する

これくらいの具体性があれば、コードに落とし込みやすいのではないでしょうか。


シートを取得する

ここからいよいよプログラミング言語に翻訳するステップです。

業界では、特定の要素や値、オブジェクトをプログラムに認識させることを「取得する」と表現することが多いようです。

《3》までに扱った「こんにちは」のコード例では、確かこんな感じでシートを取得していたと思います。

Sub test()

 Dim ws As Worksheet
 Set ws = ActiveSheet

 ...
念のためこのコードの意味を振り返っておくと、testという名前の大きな手続きの中で、wsという変数をExcelワークシート(というオブジェクト)の形で宣言し、その後wsに現在アクティブなシートをSetで代入し、紐付けています。

忘れてしまった方は、私はここで待っていますので、一度《3》を読み直してみてください。急いで先に進むよりも、基本をしっかりおさえた方が結果的に近道になると思います。


さて、以前の場合はシートを1枚しか使用しませんでしたが、今回は2枚の異なるシートの間でデータの受け渡しを行いますので、それぞれのシートを別のものとして取得してあげる必要があります。

今回は便宜上、「copyData」という名前の大きな手続きを用意しましょう。以前コードを書いていた場所の「End Sub」の下に続けて書いてしまって構いません。

~「こんにちは」のコードが書いてある場所~
End Sub




Sub copyData()

    ・アクティブなシートの
    ・この範囲のセルの
    ・値にアクセスして
    ・すべてを記憶する

    ・別なシートの
    ・この範囲のセルの
    ・値にアクセスして
    ・さっき記憶したデータを
    ・すべて記入する

End Sub

こんな感じに書いていきます。

シートを2枚使用するということは、それぞれに変数を設けてあげる必要がありますね。ws1とws2という変数を宣言してみましょう。

形はどちらもWorksheetです。

Sub copyData()

    Dim ws1 As Worksheet
    
    Dim ws2 As Worksheet

End Sub

さて、このあとそれぞれの変数にシートを代入して行くのですが、片方は「アクティブなシート」でも良いとして、「アクティブではないシート」については個別に指定する必要がありそうです。

エクセルの中のシートを取得する方法はいくつかバリエーションがあるのですが、今回は手っ取り早く、シート名で取得する方法をご紹介します。

シート名とは、エクセルのシート選択タブの見出しに書かれている名前です。※ダブルクリックで編集できます。

コメント 2019-12-13 123944

私の画面の場合は、「Sheet1」から「Sheet2」にデータをコピーすることになりそうです。ちょっとややこしいので「コピー元」「貼り付け先」という名前に変更しておきます。

コメント 2019-12-13 150730

つまり、変数ws1にコピー元を、ws2に貼り付け先をそれぞれ代入すればよいわけですね。実際には以下のように書きます。

Sub copyData()

    Dim ws1 As Worksheet
    Set ws1 = Sheets("コピー元")
    
    Dim ws2 As Worksheet
    Set ws2 = Sheets("貼り付け先")
    
End Sub

シートを名前で取得し変数に代入する

書き方:

    Dim 変数名 As Worksheet
    Set 変数名 = Sheets("シート名")


セル範囲を取得する

続いて、セルの範囲を取得してみましょう。

以前はこのように書いていました。

 Dim rg As Range
 Set rg = Range("A1")

書き方:

 Dim 変数名 As Range
 Set 変数名 = Range("セルの範囲名")

実はこの書き方を使えば、複数のセルを含む範囲を一気に取得できてしまいます。今回は下の画像で言うところの「A1:H1」という範囲です。

コメント 2019-12-13 150730

Sub copyData()

    Dim ws1 As Worksheet
    Set ws1 = Sheets("コピー元")

    Dim rg1 As Range
    Set rg1 = Range("A1:H1")

    
    Dim ws2 As Worksheet
    Set ws2 = Sheets("貼り付け先")

    Dim rg2 As Range
    Set rg2 = Range("A1:H1")
    
End Sub

これは後々応用できれば便利そうです。


値を取得する

セルの値は、RangeオブジェクトのValueプロパティにアクセスすることで取得できます。

ちょっと言い方が意地悪でした。

つまり、「Range("セルの範囲名")」で取得したセルひとつひとつに値(今回の場合は文字列)のデータが入っているので、それをValueプロパティで呼び出してやろうということです。

取り出したいデータは文字列ですから、変数を宣言する際の形はStringでしょうか。良く分かりませんが試しにそれでやってみましょう。

Sub copyData()

   Dim ws1 As Worksheet
   Set ws1 = Sheets("コピー元")

   Dim rg1 As Range
   Set rg1 = Range("A1:H1")
   
   Dim data As String
   data = rg1.Value   


   
   Dim ws2 As Worksheet
   Set ws2 = Sheets("貼り付け先")

   Dim rg2 As Range
   Set rg2 = Range("A1:H1")
   
End Sub

これを実行していただくと、こんな感じのエラーアラートが出てくると思います。

コメント 2019-12-13 155821

デバッグ(D)をクリックすると、「data = rg1.Value」の行がハイライトされたのではないでしょうか。

これはExcelが、「ここの行でエラーが発生しました」と教えてくれているサインです。

この行で「型が一致しません」ということなので、おそらく宣言したときの変数(data)の形と、代入しようとした値(rg1.Value)の型が合わなかったという意味だと思います。

文字列がひとつしか入らない箱に、無理やり複数の文字列を入れようとして、案の定失敗したと考えて頂くとイメージしやすいでしょうか。

画像11


コメントアウト

さて困りました。こうなるとプログラムは頑固なので、適切な変数の型が分からないと先に進ませてくれそうにありません。

このままエラーの修正方法についてお話したいのですが、既に5000文字を越えてしまっていますね。この先はちょっと盛り沢山になってしまいそうなので、続きはまた次回に持ち越しとさせてください。

消化不良気味ですみません。なるべく早く投稿できるように努力致しますので、何卒宜しくお願い致します。

お疲れ様でした。





ご読了ありがとうございました。
こんなやまびこですが、人生の時間をほんのちょっとだけ分けてあげてもいいよという方は、フォローを頂けると大変喜びます。


【だいたい平日18時頃に更新中】

Twitter:
https://twitter.com/echoyamabiko
@echoyamabiko

note:
https://note.com/echo_yamabiko

はてなブログ:
https://echo-yamabiko.hatenablog.com/

※内容は基本的に同じなので、一番身近なアカウントでのフォローをお勧め致します。


【匿名での質問や感想はこちらが便利です】

やまびこへの質問箱:
https://peing.net/ja/echo_yamabiko?event=0






ちなみに

再びこんにちは。ちなみにのコーナーです。

ここでは本編で語りつくせなかった細かいポイントについてお話させていただいております。

ちょっとマニアックというか、必ずしも初心者のためになるとは限らないノイズっぽい情報が載っているので、混乱を避けたい方はそっと閉じることをお勧め致します。


え、Rangeが同じところを取得してない?

Sub copyData()

    Dim ws1 As Worksheet
    Set ws1 = Sheets("コピー元")

    Dim rg1 As Range
    Set rg1 = Range("A1:H1")

    
    Dim ws2 As Worksheet
    Set ws2 = Sheets("貼り付け先")

    Dim rg2 As Range
    Set rg2 = Range("A1:H1")
    
End Sub

その通りです。次回の最後に、「エラーは出ないのに正しく動かない!」という状況を演出してトラブルシューティングを行うために、今回はあえて間違ったコードを記述しています。

《3》のちなみににも書きましたが、異なる2つのシートのセル領域を正しく取得するためにはシートオブジェクトの中でRangeプロパティを起動する必要があります。

今回のコード、途中までですが、正しくは以下のようになります。

Sub copyData()

    Dim ws1 As Worksheet
    Set ws1 = Sheets("コピー元")

    Dim rg1 As Range
    Set rg1 = ws1.Range("A1:H1")

    
    Dim ws2 As Worksheet
    Set ws2 = Sheets("貼り付け先")

    Dim rg2 As Range
    Set rg2 = ws2.Range("A1:H1")
    
End Sub


コピペするだけでこんなに難しいの!?

えっと、これについては半分Yes、半分Noといった感じです。

実は今回実現したいことをプログラムするだけなら、もっと簡単に書くことができるからです。

普段私たちが行っている、いわゆる「コピペ」という作業は、特定のデータを「クリップボード」と呼ばれる領域に一時保存し、そこから貼り付けを行っています。

厳密にこれと同じことをVBAで実行すると、こんな感じのコードになるでしょう。

Sub copyData()

    Dim ws1 As Worksheet
    Set ws1 = Sheets("コピー元")

    Dim rg1 As Range
    Set rg1 = ws1.Range("A1:H1")

    
    Dim ws2 As Worksheet
    Set ws2 = Sheets("貼り付け先")

    Dim rg2 As Range
    Set rg2 = ws2.Range("A1:H1")

    

    
    rg1.Copy rg2 'rg1をコピーしてrg2に貼り付ける
    
End Sub

実はこれだけで、コピー元から貼り付け先に正常にコピペされます。もちろんエラーも出ません。

Copyなんて便利そうなのがあるじゃん!なんだよ!」とお怒りの方、お気持ちはとても良く分かります。ただちょっとだけ、言い訳を聞いて下さい。


「VBA セル範囲 コピペ」でGoogle検索をすると、ほとんどのサイト様がこのCopyメソッドを紹介しています。実際かなり便利です。

でも少し考えてみてください。このメソッドを使うと、データがクリップボードに保存され、そのデータが貼り付けされる仕組みです。

このクリップボードはユーザーが普段使っているものと共通ですから、プログラムが動いている間、ほかの作業で「コピー」をしただけで、クリップボードの情報が上書きされてしまうということです。

つまりCopyメソッドを使用した場合、完成したツールが動いている間、ユーザーがふとコピペをしただけで不具合が発生する欠陥品に仕上がってしまうということです。

便利なものごとには必ず代償が存在します。ActiveSheetをあまり使いたくない理由もこれと似ています。実行中にユーザーが別のExcelを開いて作業をするだけで、アクティブなシートは変化してしまうからです。


また、私たちは本来このコピーと貼り付けの間に「並べ替え」という作業を挟む必要がありました。

その工程をあとで追記しやすくするためにも、一旦値を変数に格納して処理する必要があったわけです。

ただのコピペ、されどコピペです。これを少しでもエレガントに行うために、ひとつひとつ基礎を積み上げて勉強していけたらと思います。

何卒宜しくお願い致します。


記事は基本無料公開にしようと思うので、やまびこの明日のコーヒー代くらいは恵んでやってもいいぜという方は、お気軽にご支援ください。気長にお待ちしております。