ExcelVBAでWordの指定の文字をチェック後にPDFに変換するマクロ

業務中にWordを使った文章の中で指定の文字列をチェックして、特に問題がなければPDFに変換する、という作業があったりはしないでしょうか。

 

一見すると単純で簡単な作業のように見えますが、実際はパターンがいくつかあってチェックする箇所も内容も違うといったこともあるでしょう。そのため、業務量が増えてくると注意力が散漫になったり、月替わりでチェックする条件が変わったりするとミスが発生してしまう可能性も高くなってきます。

 

こういった場合に人間の目視ではなく、機械やシステムが自動でチェックして作業までしてくれたら非常に楽になるのになぁと考えた事はないでしょうか。

 

業務中に自分が担当する部分でそのようなケースがあったので、サンプルのサンプルという感じで本当に簡単ではありますが、今回の状況を考えたコードを整理していこうと思います。

ExcelVBAでWordの指定の文字をチェック後にPDFに変換するコード

ちょっと長くなってしまいますが、以下が「ExcelVBAでWordの指定の文字をチェック後にPDFに変換するコード」になります。Excelの標準モジュールに貼り付けます。動作はExcel2013、Word2013で確認しています。

Public wd As Variant
Sub テスト()
Set wd = CreateObject("Word.Application")
wd.Visible = True
Dim wdDoc As Variant
Dim i As Long
Dim FSO As Object
Dim f As Object
Dim P As String
Dim flg As Integer
P = ThisWorkbook.Path
Set FSO = CreateObject("Scripting.FileSystemObject")
flg = 0
'Wordファイルだけ処理
For Each f In FSO.GetFolder(P).Files
 If FSO.GetExtensionName(f.Path) Like "*doc*" And Not (f.Path Like "*$*") Then
  Set wdDoc = wd.Documents.Open(ThisWorkbook.Path & "\" & Dir(f.Path))
  KanriNo = Sheets("書類チェック").Range("C3")
  Stype = Sheets("書類チェック").Range("C4")
  ShisyaName = Sheets("書類チェック").Range("C5")
'----------------------------------------------------------------
  Call チェックとPDF保存(KanriNo, Stype, ShisyaName)
'----------------------------------------------------------------
  Set wdDoc = Nothing
  flg = 1
 End If
Next f
wd.Visible = False
Set wd = Nothing
Set FSO = Nothing
If flg = 1 Then
MsgBox "文書のチェックとPDFへの変換が終わりました。", vbInformation
Else
MsgBox "チェックするWord文書がありませんでした。", vbInformation
End If
End Sub
Sub チェックとPDF保存(KanriNo, Stype, ShisyaName)
Dim myFileName As String
Dim myFilePath As String
Dim myDoc As Variant
Dim intPos As Integer
'---------------------------------------------------------------------
'2行目から管理番号をチェックする
Dim Rng As Variant
Set Rng = wd.ActiveDocument.Range(0, 60)
With Rng.Find
.Text = KanriNo
.MatchByte = True
.MatchCase = True
If .Execute = False Then
MsgBox "番号が一致しません。", vbInformation
Set myDoc = Nothing
End
End If
End With
Set Rng = Nothing
'3行目から書類の種類を検索する
Set Rng = wd.ActiveDocument.Range(0, 60)
With Rng.Find
.Text = Stype
.MatchByte = True
.MatchCase = True
If .Execute = False Then
MsgBox "書類の種類が一致しません。", vbInformation
Set myDoc = Nothing
End
End If
End With
Set Rng = Nothing
'5行目から支社名を検索する
Set Rng = wd.ActiveDocument.Range(0, 60)
With Rng.Find
.Text = ShisyaName
.MatchByte = True
.MatchCase = True
If .Execute = False Then
MsgBox "支社名が一致しません。", vbInformation
Set myDoc = Nothing
End
End If
End With
Set Rng = Nothing
'-------------------------------------------------------------------
Set myDoc = wd.ActiveDocument
'拡張子のない名称を取得
myFileName = myDoc.Name
intPos = InStrRev(myFileName, ".")
myFileName = Left(myFileName, intPos - 1)
'PDFファイルで保存
myFilePath = myDoc.Path 'Wordファイルと同じフォルダ
myDoc.ExportAsFixedFormat _
OutputFileName:=myFilePath & "\" & myFileName & ".pdf", _
ExportFormat:=17
'「https://tyama-blog.blog.ss-blog.jp/2017-01-18」を参照
'wdExportFormatPDF=17
'---------------------------------------------------------------------
wd.ActiveDocument.Close
Set myDoc = Nothing
End Sub

上記のコードは大きく2つに分けられます。

 

ひとつめは指定のWordファイルを表示させたり、チェックする内容を変数に格納したりする「テスト」プロシージャ

 

ふたつめは、ひとつめのプロシージャで設定した文字列を元に、開いたWordファイルの中身の指定の部分のチェックとPDFへの変換をする「チェックとPDF保存」プロシージャになります。

 

今回のプログラムを実行できるようにするには、事前の準備としてまずデスクトップなどに適当にフォルダを作ります。その中にExcelファイルを作成し、そのファイルのモジュールに今回のコードをコピペします。

 

そうしたら、同じフォルダ内にチェックとPDF変換したいWordファイルを入れます。ちなみに今回使ったのはどのようなWordファイルかというと、インターネット上にあるフリーの送付状などの文章を一部修正して使わせていただきました。

書類の文面とチェック箇所

サンプルなので適当にありそうな文章を選びつつも今回のコード用として業務用として、赤枠の部分などに修正を加えています。今回のコードでチェックする箇所は画像の赤枠の部分です。

 

Wordの文書のチェックとPDF変換したい場合は、上の画像のような文章の形式である必要があります。このふたつのプロシージャについてもう少し詳しく説明していきます。

ひとつめの「テスト」プロシージャの大まかな流れ

見やすいようにと確認のために以下のひとつめの「テスト」プロシージャを再掲します。

Public wd As Variant
Sub テスト()
Set wd = CreateObject("Word.Application")
wd.Visible = True
Dim wdDoc As Variant
Dim i As Long
Dim FSO As Object
Dim f As Object
Dim P As String
Dim flg As Integer
P = ThisWorkbook.Path
Set FSO = CreateObject("Scripting.FileSystemObject")
flg = 0
'Wordファイルだけ処理
For Each f In FSO.GetFolder(P).Files
 If FSO.GetExtensionName(f.Path) Like "*doc*" And Not (f.Path Like "*$*") Then
  Set wdDoc = wd.Documents.Open(ThisWorkbook.Path & "\" & Dir(f.Path))
  KanriNo = Sheets("書類チェック").Range("C3")
  Stype = Sheets("書類チェック").Range("C4")
  ShisyaName = Sheets("書類チェック").Range("C5")
'----------------------------------------------------------------
  Call チェックとPDF保存(KanriNo, Stype, ShisyaName)
'----------------------------------------------------------------
  Set wdDoc = Nothing
  flg = 1
 End If
Next f
wd.Visible = False
Set wd = Nothing
Set FSO = Nothing
If flg = 1 Then
MsgBox "文書のチェックとPDFへの変換が終わりました。", vbInformation
Else
MsgBox "チェックするWord文書がありませんでした。", vbInformation
End If
End Sub

上記のコードの大まかな流れとしては、Wordを操作することになるのでまず最初に

Set wd = CreateObject(“Word.Application”)

という形で「Wordオブジェクト」を生成し、オブジェクト変数wdに格納します。

 

次はファイルシステムオブジェクトを生成します。次に今回のコードを貼り付けるExcelファイルが存在するフォルダ内からWordファイルを探していきます。

 

次は以下のようなコードになります。

KanriNo = Sheets(“書類チェック”).Range(“C3”)

Stype = Sheets(“書類チェック”).Range(“C4”)

ShisyaName = Sheets(“書類チェック”).Range(“C5”)

上記のコードの意味は、以下の画像に入力されているExcelの「書類チェック」シートの指定の箇所からWord文書のチェックしたい箇所ごとに「どのような文字列をチェックしたいか」を入力できるようになっています。

書類チェックシート

例えば番号項目は既に載せたWord文書の画像の右上の赤枠の部分、書類の種類はWord文書の中央上の赤枠の部分、会社名はWord文書の左上の赤枠の部分に該当します。今回はサンプルのサンプルぐらいの位置づけなので、本当に簡単な設定だけにしてあります。

 

コード上で書類チェックシートで入力した文字列を指定の変数に格納後は、次のコードで実際にWord文書の指定の箇所のチェックとPDF変換を実行していきます。

Call チェックとPDF保存(KanriNo, Stype, ShisyaName)

今回のコードが入ったExcelファイルと同じ階層にWordファイルがひとつもなかった場合、flgに1が入らないので次のIf文で「チェックするWord文書がありませんでした」のメッセージが表示されます。

If flg = 1 Then

 MsgBox “文書のチェックとPDFへの変換が終わりました。”,

 vbInformation

Else

 MsgBox “チェックするWord文書がありませんでした。”,   

 vbInformation

End If

Wordファイルがあって、なおかつ指定のWord文書で指定の箇所に問題がなければflgに1が入り、「文書のチェックとPDFへの変換が終わりました。」の文字列が表示されるようになっています。

ふたつめの「チェックとPDF保存」プロシージャの大まかな流れ

見やすいようにと確認のために以下のふたつめの「チェックとPDF保存」プロシージャを再掲します。

Sub チェックとPDF保存(KanriNo, Stype, ShisyaName)
Dim myFileName As String
Dim myFilePath As String
Dim myDoc As Variant
Dim intPos As Integer
'---------------------------------------------------------------------
'2行目から管理番号をチェックする
Dim Rng As Variant
Set Rng = wd.ActiveDocument.Range(0, 60)
With Rng.Find
.Text = KanriNo
.MatchByte = True
.MatchCase = True
If .Execute = False Then
MsgBox "番号が一致しません。", vbInformation
Set myDoc = Nothing
End
End If
End With
Set Rng = Nothing
'3行目から書類の種類を検索する
Set Rng = wd.ActiveDocument.Range(0, 60)
With Rng.Find
.Text = Stype
.MatchByte = True
.MatchCase = True
If .Execute = False Then
MsgBox "書類の種類が一致しません。", vbInformation
Set myDoc = Nothing
End
End If
End With
Set Rng = Nothing
'5行目から支社名を検索する
Set Rng = wd.ActiveDocument.Range(0, 60)
With Rng.Find
.Text = ShisyaName
.MatchByte = True
.MatchCase = True
If .Execute = False Then
MsgBox "支社名が一致しません。", vbInformation
Set myDoc = Nothing
End
End If
End With
Set Rng = Nothing
'-------------------------------------------------------------------
Set myDoc = wd.ActiveDocument
'拡張子のない名称を取得
myFileName = myDoc.Name
intPos = InStrRev(myFileName, ".")
myFileName = Left(myFileName, intPos - 1)
'PDFファイルで保存
myFilePath = myDoc.Path 'Wordファイルと同じフォルダ
myDoc.ExportAsFixedFormat _
OutputFileName:=myFilePath & "\" & myFileName & ".pdf", _
ExportFormat:=17
'「https://tyama-blog.blog.ss-blog.jp/2017-01-18」を参照
'wdExportFormatPDF=17
'---------------------------------------------------------------------
wd.ActiveDocument.Close
Set myDoc = Nothing
End Sub

このプロシージャのおおまかな流れとして、まず開いたWord文書の2行目にある番号、3行目の書類の種類、5行目の会社名(支社名)をチェックしていきます。

 

これはExcelの書類チェックシートで入力した各項目の文字列が含まれているかをチェックしています。この部分のポイントは文字列を検索する機能がある「Find」になるかと思います。

 

Wordにおける文字列の検索のポイントとして『最速攻略 Word マクロ / VBA徹底入門 〔Word 2013/2010/2007対応版〕』には次のように書かれています。

P154

Wordの通常の操作では、文字列範囲を選択していない状態で検索を実行すると、カーソル位置以降で最初に発見された検索文字列が選択されます。

 

また、範囲を選択した状態で検索を実行すると、選択範囲内で最初に発見された検索文字列が選択されます。

Findを実行する前に、各箇所で

Set Rng = wd.ActiveDocument.Range(0, 60)

というコードがあるかと思います。これはそのまま検索を実行すると、Wordがその文書全部の文字列の中から指定の文字列を検索してしまうので、0字から60文字目の間で検索するというコードです。

 

このRangeメソッドの引数は次のようになっています。

P111

書式 Documentオブジェクト.Range(Start,End)

解説 文書中の挿入位置または文字列範囲を表すRangeオブジェクトを返します。

・Start

挿入位置または文字列範囲の開始位置を、数値で指定します。省略した場合は本文の先頭(0)が開始位置になります。

・End

文字列範囲の終了位置を数値で指定します。省略した場合は本文の末尾が終了位置になります。StartとEndを両方省略すると、本文全体が指定されます。

・戻り値

StartからEndの位置までの文字列範囲を表すRangeオブジェクトを返します。StartとEndに同じ数値を指定した場合は、その挿入位置を表すRangeオブジェクトを返します。

次に以下のコードについて説明します。

.Text = ShisyaName

.MatchByte = True

.MatchCase = True

FindオブジェクトのtextプロパティでExcelの方で入力した文字列を自動で指定するようになっています。MatchByteプロパティで半角と全角を区別するかどうかを設定、MatchCaseプロパティではアルファベットの大文字・小文字を区別するかどうかを設定します。

 

次のIf文を利用したExcuteメソッドで、ちゃんと実行されれば指定の文字列が存在するということで次の文字列のチェックに移動します。実行されなければ指定の文字列が存在しなかったということで、そこでメッセージが表示されてプログラムが終わるようになっています。

 

3つの文字列をチェックして何も問題がなければ、WordファイルをPDFに変換してExcelファイルと同じ階層に出力するというコードになっています。

まとめ

最初は今回のようなコードではなくExcelにひとつめのプロシージャを入れて、ふたつめのプロシージャをWordの方に入れて実行するようにしていました。

 

しかしそれだと、チェックとPDF変換をしたいWordファイルができる度にそのファイルにふたつめのプロシージャを入れないといけないのでExcelの方にまとめるようにしました。

 

この段階で手こずったのがWordオブジェクトの操作です。Excelの方にまとめた後に実行するとすぐにデバッグの画面になってしまいましたが、すぐに「Wordオブジェクト」が操作できていないことに気付きました。

 

そこから1行目にある「Public wd As Variant」を入力してどちらのプロシージャでもWordオブジェクトを操作できるようにしました。

 

この部分が改善されると、次に躓いてもすぐに「Wordオブジェクト」がないから止まるんだなとわかります。ですからすぐにコードの最初の部分に「wd」を入れて実行が進むようにしました。

 

一番てこずったのは、ふたつめのプロシージャの

myDoc.ExportAsFixedFormat _ OutputFileName:=myFilePath & “\” & myFileName & “.pdf”, _ ExportFormat:=17

の部分です。

 

最初、ExportFormat:=wdExportFormatPDFにしていたのですが、この部分の解決策がどうしてもわからずインターネットで調べた所、wdExportFormatPDFではなく数値の「17」にすると良いとのことでした。

 

この理由について、参考URLはコード内に

「https://tyama-blog.blog.ss-blog.jp/2017-01-18」を参照

という形で記述しましたので詳細はこちらを見ていただければと思います。

 

今回のコードは、本当にサンプルという感じなので、実際に業務で使えるようにしたい場合はちゃんと業務に合うようにしっかり作りこむ必要があります。

 

今回のコードを作っていて思ったのは、当たり前と言えば当たり前なのですが、OutlookにはOutlookのルール、AccessにはAccessのルールがあるように、WordにはWordのルールがあるということです。

 

一見すると同じように見えるのですが、それぞれのアプリケーションの性質を理解していないとなかなか思うように進めることが出来ません。逆に性質やルールがわかるとコードを作るのがすごく楽になります。

 

VBAに限らず、JavaScriptや他のプログラミング言語でもそうですが、対象のアプリケーションの性質や使い勝手を理解できるようになると、それに対して使うプログラムも作りやすくなっていくのだろうなぁと思いました。

あわせて読みたい

こんな記事も読まれています

コメント