PDF文書の翻訳ツールを作る2(クリップボードの中身を取得する)
熱くなったり寒くなったり、お外も忙しい感じな今日この頃です
こんちくわ 壁|ω・)ノ
さて、前回の記事の続きです。
今回は作った翻訳ツールで利用したクリップボード内の文字列情報取得について紹介したいと思います。
でわいきます ̄▽ ̄)ノ
Contents
- 前回の記事では・・・
- それで、作った翻訳マクロではどんな工夫したの?
- クリップボードの中身を取り出して変数に代入する
- クリップボードの中身を空にする
- クリップボードの中身が空かどうかを確認する
- クリップボードの中身を返すFunction プロシージャ
- まとめ
- 因みに
前回の記事では・・・
以下のことを書きました
- 英語のPDF文献をコピーしてWeb翻訳ツールにペーストすると、文章の途中に改行コードが挿入された状態でペーストされてしまうために翻訳がうまく機能しない
- 改行コード(Chr(10)/vbCrLf)を半角スペースに変更するマクロを作ったけれども、ワークシートにコピペして、処理してWebページに貼りつけるなど翻訳操作にメッチャ手間がかかる
操作の多くを自動化して手間を削減し、かつGoogleよりも精度が高いDeepL翻訳サイトを利用するマクロを作った
それで、作った翻訳マクロではどんな工夫したの?
前回紹介した ”改行 → 半角スペース変換” マクロを使った翻訳作業では
1. 文献の該当部部分をコピー 2. エクセルのワークシートのどっかのセルをダブルクリック 3. ペースト 4. VBE起動 5. 改行をスペースに変換マクロを起動 6. 出来上がった文章が入ったセルをダブルクリッ 7. 文書全体を選択 8. コピー 9. ブラウザを起動(DeepL)して翻訳サイトにアクセス 10. 文書をペーストしてEnter 11. 待つ
という手順が必要だったわけですが、PDF文書 → ワークシート, ワークシート → DeepLサイト へのコピペがたるいんですよねぇ。全部手作業だし。。ってか、結局改行処理しかマクロ使ってないし。
そこでふと気が付いたのが、
クリップボードの中身を直接取り出して変数に入れれたらいいぢゃん!
なんかできる気がする。。
そこで、Google先生に伺ったところ・・・、
ありました。VBAで取り出す方法が!
クリップボードの中身を取り出して変数に代入する
クリップボードの中身を取得するにはMSFormsライブラリの DataObject クラス
のメンバーであるGetFromClipboardメソッドと GetText メソッド
を利用します。
さらに、MSFormsライブラリを利用する下準備として、Microsoft Forms 2.0 Object Library を有効にする
ための参照設定を行います(ツール → 参照設定 → "Microsoft Forms 2.0 Object Library" チェックボックスをオンにする)
コード例
Sub クリップボードの中身を取り出す() 'クリップボードの中身は文字列な前提です Dim cbContents As Variant Dim clipBoard As MSForms.DataObject: Set clipBoard = New MSForms.DataObject With clipBoard Call .GetFromClipboard cbContents = .GetText End With Debug.Print cbContents End Sub
DataObjectクラスのメンバーを利用するために、DataObjectクラスから "clipBoard" という名前のインスタンスを新しく生成(New)しました。その後、GetFromClipboard メソッドでクリップボードをインスタンス "clipBoard" に一旦移して、GetTextメソッドを使って変数 cbContents に代入しています。
これでめでたくクリップボードの中身を取り出す術を手に入れました。
クリップボードの中身を空にする
実際の翻訳作業ではPDF文書の コピー → 翻訳 を何度も繰り返すことが想定されます(少なくとも私はやる)。それで、直前にクリップボードに残っていた文字列が悪さをしないとも限らないわけで、処理としてはきちんと中身を変数に移した後はクリップボードは空に
しておいた方がいい気がしました。
この空にする処理なのですが、Google先生に伺ったところ Windows API を利用との答えが返ってきて ('ω')クッ となっていたところ、Application.CutCopyMode = False
が使えるということに偶然気が付きました。
ただし単独ではだめなので、ワークシートのどこかのセルのコピーとセットにします。
Sub ClearClilpBoad() 'ワークシートのどこでもいいのでコピーした後に、 Application.CutCopyMode = Falseしたらクリップボードが空になる ' Application.CutCopyMode = False単独では空にならない ActiveSheet.Range("A1").Copy Application.CutCopyMode = False End Sub
(十分に検証したわけでわありませんが、ワークシートのセルを一旦クリップボードに入れるだけなので、セルに何が入ってても大丈夫かなと。)
クリップボードの中身が空かどうかを確認する
次に、確認作業のオハナシです。
PDF文書のコピーは "選択 → 右クリ → コピー" でもいいですが、"Ctrl + C" を利用する方も多いかと思います。で、この Ctrl + C はたまにうまくいかないことがある気がします(筆者の印象のみです。未検証です)。それでもし、うまくクリップボードに目的の文字列が入らなかった場合にはもちろん翻訳が失敗するわけで、それがプログラムの不具合と誤認されては癪に障る ユーザーに不都合がないようコピーに失敗した旨教えてあげないといけません。
そこで、クリップボードに中身が入っていることを確認する処理を挟むことにしました。
VBAにはクリップボードの状態を確認するプロパティがちゃんと備え付けられていて、Application.ClipboardFormats(1)
の値を参照することで、クリップボードに何のフォーマットデータが入っているか確認できます(事前の参照設定は、なんと不要)。
Value | Description |
---|---|
0 | Text |
1 | Value |
2 | Picture |
5 | CSV format |
などなど(詳しくは公式 https://docs.microsoft.com/ja-jp/office/vba/api/excel.xlclipboardformat をご覧ください)。
それで、空の場合は Application.ClipboardFormats(1)=-1
となりますので、これを条件構文に組み込めばよいですね。
クリップボードの中身を返すFunction プロシージャ
というわけで、プリップボードの中身を返す機能単位として以下のようなFunctionプロシージャを作りました
Function ClipBordContents() As String 'クリップボードの中身を取り出す 'クリップボードの中身有無判定。空なら Application.ClipboardFormats(1) =-1 となる ' ”vbEmpty” を使いたいので、クリップボードが空なら合計値を0(ゼロ)にする Dim cbContent As Variant: cbContent = Application.ClipboardFormats(1) + 1 Dim clipBoad As MSForms.DataObject: Set clipBoad = New MSForms.DataObject With clipBoad If Not cbContent = vbEmpty Then Call .GetFromClipboard ClipBordContents = .GetText Else Call MsgBox("文書がコピーできてませんよう", vbExclamation) End End If End With Call ClearClilpBoad End Function '-------------------------------------- Sub ClearClilpBoad() 'ワークシートのどこでもいいのでコピーして、 Application.CutCopyMode = Falseしたらクリップボードが空になる ' Application.CutCopyMode = False単独では消えない ActiveSheet.Range("A1").Copy Application.CutCopyMode = False End Sub
戻り値のあるFunction プロシージャですが、引数として受け取るものがありませんので、関数呼び出しとしては
a=ClipBordContents()
と、教科書に書いてある関数の記述みたいになりますが、まぁしょうがないでしょうか。。 かっこ()は省略可能ですが、省略するとそれが Functionプロシージャ であることが余計わかりにくくなるので、つけておいた方がいい気がします。
まとめ
本日の記事では、以下のことを紹介しました。
- 当初は手作業が多くってたるかった一連の翻訳作業を全体としてマクロ化することでかなり楽ちんになった
- コピーした文書の改行処理をメモリ上で行ったことで、文字列情報の転記が操作をなくしたことがポイント
- クリップボード情報を変数に取り込む処理として
MSFormsライブラリの DataObject クラス
のメンバーであるGetFromClipboardメソッドと GetText メソッド
が利用できる
クリップボードの中身を取り出す処理というのは実は今回初めて書きましたが、実際に書いてみると思ってたよりもハードルが高くなかったと感じました。クリップボードを使ったデータのやり取りはエクセル外アプリケーションとのデータやり取りに利用できると思います。もちろん他にもっといい方法はあるのでしょうが、今回のコーディングを通じてエクセル外アプリをVBAで操作する得体のしれない恐れみたいなものがかなり軽減された気がしました。
次回はDeepLサイトに取り出した文字列を貼るコードを紹介したいと思います
でわまた~  ̄▽ ̄)ノシ
因みに
今回は取り出すだけでしたが、同じくMSFormsライブラリの DataObject クラス
メンバーのSetTextメソッド、PutInClipBoardメソッドを使って書き込む
こともできます。
Sub クリップボードに文字列をセットして取り出す() Dim cbContents As Variant Dim clipBoard As MSForms.DataObject: Set clipBoard = New MSForms.DataObject With clipBoard 'クリップボードにセット Call .SetText("こんちくわ") Call .PutInClipboard 'クリップボードから取り出す Call .GetFromClipboard cbContents = .GetText End With Debug.Print cbContents End Sub
SetTextメソッドで文字列をインスタンスにセットして、PutInClipBoardメソッドでクリップボードに書き込むという感じで、ちょうど取り出しとは逆のプロセスなんですね。