プロが教えるわが家の防犯対策術!

ワードの文書中の文字列をマクロで書き換える。
準備:ワード文書(「文書1.docx」)にて 
本文中に 「すずき」
表に 「すずき」
ヘッダー、フッターに 「すずき」
ふたつのTextBox中に 「すずき」

ワードのマクロ、エクセルでのマクロを、とにかく、試行錯誤で完成させました。
しかし、意味が分からない部分があります。
下記にて①、②、③、そして、安定の観点からのサジェスチョンを
お願いしたいと思います。
方法は、これだけではないと思います。多分、使うクラス、メンバーの違い
だと思います。何がしかのサジェスチョンをいただければ幸いです。
宜しくお願い致します。
尚、環境は Windows10(Windows8.1 32bitからup),Office2010です。

'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Sub ワードでのマクロ()
Dim sec As Section
Dim hdr As HeaderFooter
Dim i as Integer

' 文章全体に対して、置換を実行する=====================
ActiveDocument.Range(0, 0).Select ’①必要性はない
Selection.WholeStory       ’①仮に入れるなら、どんな場合?

strFind = "すずき"
strReplace = "鈴木"

With Selection.Find
.Text = strFind
.Replacement.Text = strReplace
.Wrap = wdFindContinue
.Execute Replace:=wdReplaceAll
End With

' フッターに対して、置換を実行する=====================
For Each sec In ActiveDocument.Sections ’②For eachの必然性?
For Each hdr In sec.Footers        ’②同様に
With hdr.Range.Find ’3回,回るが、フッタが3つあるわけではない!?
.Text = strFind
.Replacement.Text = strReplace
.Forward = True
.Wrap = wdFindContinue
.Execute Replace:=wdReplaceAll
End With
Next
Next

' ヘッダーに対して、置換を実行する=====================
For Each hdr In ActiveDocument.Sections.Item(1).Headers
’③Itemを使うことでも、OKであったが、やはりメンバーはitem(1)だけのようだ。
' このからくりはどうなっているのであろうか?
With hdr.Range.Find
.Text = strFind
.Replacement.Text = strReplace
.Forward = True
.Wrap = wdFindContinue
.Execute Replace:=wdReplaceAll
End With
Next

'Shapeオブジェクトに対して置換実行=================
For i = 1 To ActiveDocument.Shapes.Count 
’For NextはTextBoxの数だけ。従って理解可。
ActiveDocument.Shapes(i).Select
Selection.Find.ClearFormatting       
Selection.Find.Replacement.ClearFormatting 
With Selection.Find
.Text = strFind
.Replacement.Text = strReplace
.Forward = True
.Wrap = wdFindContinue
.Execute Replace:=wdReplaceAll
End With
Next i
End Sub

'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Sub エクセルでのマクロ()
Dim WdApp As Word.Application
Dim WdDoc As Word.Document

'ワード 文章全体に対して、置換を実行する===================
Set WdDoc = GetObject("C:\文書1.docx") ’ワード文書をオープン
Set WdApp = WdDoc.Application
WdApp.Visible = True
WdDoc.Activate
strFind = "すずき"
strReplace = "鈴木"
With WdDoc.Content.Find
.Text = strFind
.Replacement.Text = strReplace
.Forward = True
.Wrap = wdFindContinue
.Execute Replace:=wdReplaceAll
End With

' フッターに対して、置換を実行する=====================
Dim sec As Word.Section
Dim hdr As Word.HeaderFooter
For Each sec In WdDoc.Sections
For Each hdr In sec.Footers
With hdr.Range.Find
.Text = strFind
.Replacement.Text = strReplace
.Forward = True
.Wrap = wdFindContinue
.Execute Replace:=wdReplaceAll
End With
Next
Next

' ヘッダーに対して、置換を実行する=====================
For Each hdr In WdDoc.Sections.Item(1).Headers
With hdr.Range.Find
.Text = strFind
.Replacement.Text = strReplace
.Forward = True
.Wrap = wdFindContinue
.Execute Replace:=wdReplaceAll
End With
Next

'Shapeオブジェクトに対して置換実行=================
Dim myShape As Word.Shape
For Each myShape In WdDoc.Shapes
myShape.TextFrame.TextRange.Find.ClearFormatting
myShape.TextFrame.TextRange.Find.Replacement.ClearFormatting
With myShape.TextFrame.TextRange.Find
.Text = strFind
.Replacement.Text = strReplace
.Forward = True
.Wrap = wdFindContinue
.Execute Replace:=wdReplaceAll
End With
Next
WdApp.Quit

End Sub

A 回答 (2件)

No.1の回答者です。


お礼を読みました。VBAでステップインを使ってマクロの動作確認を
しているのですね。
私は、マクロについて少しずつ理解している最中であり、高度な処理を
するようなものは、理解もできていませんし書くこともできません。
ですから、いくつかの疑問に対しては、私なりに理解している範囲での
回答になりますので、違っている場合もあります。


お礼の1.について
> Selectionを入れることで、動きました
そうですか。私も理解しているわけではないのですが。
'ActiveDocument.Range(0, 0).Select
このコメントブロックを解除してもダメだったのでしょうか?

変数rngを本文領域でも使えるようにする方法もあります。
Set rng = ActiveDocument.Range(Start:=0, End:=0)
With rng.Find
.Text = strFind
.Replacement.Text = strReplace
.Wrap = wdFindContinue
.Execute Replace:=wdReplaceAll
End With
私の環境では、これで動作します。


お礼の2.について
> ' セクションごとのヘッダー・フッターで指定
> For Each sec In ActiveDocument.Sections

繰り返しが必要なのは、SectionオブジェクトにはHeadersプロパティと
Footersプロパティがあり、HeadersFootersコレクションオブジェクト
を持つためです。ここには3つの定数があり、それぞれに対して指定を
する必要があるためです。
http://www.relief.jp/itnote/archives/word-vba-he …

さらに、セクション数が複数の場合に、セクション1と次のセクション
との関係で、前セクションとリンク(前と同じ)が切れている場合に、
指定した置換設定が続いているセクションでは実行されないためです。

このことから、セクションを指定する場合は、必要なので記入します。


お礼の3.について
お礼の2.と関連しますが、HeadersFootersコレクションオブジェクト
の3つの定数ごとに処理をしますので、3回の処理をします。
 wdHeaderFooterEvenPages
 wdHeaderFooterFirstPage
 wdHeaderFooterPrimary
これをセクションごとのヘッダーとフッターで繰り返すためです。


お礼の4.について
テキストボックスのみのロックなどがあることすら知りません。
Wordだけで作成したテキストボックスなのでしょうか?
(Excelなら、個別にロックできるので)
Wordにも[編集の制限]がありますが、保護を開始して制限する範囲に、
テキストボックスのみがあるとは思えないのですが?
エラーになる部分のテキストボックスを直接確認してみてはいかが。

今回のエラーが、何が影響しているのか私にはわかりません。
On Errorステートメントでエラーを無視することはできそうですが、
これを使うのは原因がわかっている場合のほうが良いみたいです。
http://officetanaka.net/excel/vba/statement/OnEr …

ちなみに、Wordのバージョンなどの環境を書いたほうが、お互いの
違いによるトラブルを避けることができると思いますよ。
私の場合はWord2013なのですが、No.1の回答で提示したマクロは、
以前所持していたWord2002でも実行できたと思います。
    • good
    • 0
この回答へのお礼

遅くなりました。
ありがとうございます。
まだ、よくわかっていませんが、兎に角先に進めます。
助かりました。

お礼日時:2015/11/12 21:10

前回と関連する質問ですか?


https://oshiete.goo.ne.jp/qa/9099249.html

WordのVBAにおける置換の対象は、[検索]ダイアログで[検索する場所]
として表示されるものすべてを指定する必要があります。
本文だけでなく、ヘッダー・フッター、脚注やテキストボックスなどのそれぞれに対して指定しないとならないので、それぞれを指定する必要があります。

今回の質問マクロでも、メイン文書(本文領域)とヘッダーとフッター、
テキストボックスそれぞれを指定していますよね。

この検索をする対象を探すときに、その領域の一番最初へとカーソルが来るようにすると、[ワイルドカード]を使った検索のときに検索対象が
外れる不具合を防ぐことができるおまじないみたいなものらしいです。
これが①を最初に書く理由です。

②については不要だと思います。理由としては、検索領域を選択状態に
する必要があるかどうかによります。
質問のマクロだと Selection.Find と Range.Find の両方を使いわけで
利用していますが、複数の領域がある場合は Range.Find だけで検索をしたほうがわかりやすくなると思います。
この場合はWholeStoryを使ってSelectionする必要がないと思います。
http://ameblo.jp/gidgeerock/entry-10555149798.html
http://ameblo.jp/gidgeerock/entry-10558772411.html

Selection.Find を使う場合は、検索条件をすべて書かないとエラーに
なる場合があるのに対して、Range.Find は必要な条件のみ書けば済む
利点もあります。

ですから

' 文章全体に対して、置換を実行する=====================
ActiveDocument.Range(0, 0).Select ' ワイルドカードでは必要

strFind = "すずき"
strReplace = "鈴木"

With Range.Find
.Text = strFind
.Replacement.Text = strReplace
.Wrap = wdFindContinue
.Execute Replace:=wdReplaceAll
End With

で本文領域は問題なく検索し、置換が実行されるはずです。

ヘッダーやフッター、テキストボックスの場合は、それぞれの領域で
変数を用意し、その変数をRangeしてからRange.Findすることで対応
します。以下は、これらを組み込んで私なりに書いてみたものです。

Sub Wordで置換マクロ()

Dim strFind As String
Dim strReplace As String
Dim sp As Shape
Dim sec As Section
Dim hdr As HeaderFooter
Dim rng As Range

'ActiveDocument.Range(0, 0).Select ' ワイルドカードでは必要

strFind = "Word"
strReplace = "Excel"

With Range.Find
.Text = strFind
.Replacement.Text = strReplace
.Wrap = wdFindContinue
.Execute Replace:=wdReplaceAll
End With

' セクションごとのヘッダー・フッターで指定
For Each sec In ActiveDocument.Sections

' フッターの場合
For Each hdr In sec.Footers
Set rng = hdr.Range
With rng.Find
.Text = strFind
.Replacement.Text = strReplace
.Execute Replace:=wdReplaceAll
End With
Next

' ヘッダーの場合
For Each hdr In sec.Headers
Set rng = hdr.Range
With rng.Find
.Text = strFind
.Replacement.Text = strReplace
.Execute Replace:=wdReplaceAll
End With
Next

Next

' テキストボックスの場合
For Each sp In ActiveDocument.Shapes
If sp.Type = msoTextBox Then
Set rng = sp.TextFrame.TextRange
With rng.Find
.Text = strFind
.Replacement.Text = strReplace
.Execute Replace:=wdReplaceAll
End With
End If
Next

End Sub

ExcelでWordを操作するマクロについては記載しません。
上記マクロを参考にして、Excelに移植してください。

質問にあるマクロは、いろいろなサイトのWord用のマクロを参考にした
ようでが、書き方を統一したほうがメンテナンスしやすいと思います。
    • good
    • 0
この回答へのお礼

ありがとうございます。

試してみました。
1.しかし、「オブジェクトがありません」と出てしまいました。
メイン本文の置換の頭です。

試行錯誤の結果
With Selection.Range.Find
.Text = strFind
.Replacement.Text = strReplace
.Wrap = wdFindContinue
.Execute Replace:=wdReplaceAll
End With

Selectionを入れることで、動きました。
ワードにおけるselectionが、まだ、きちんと理解できていませんが。

2. ' セクションごとのヘッダー・フッターで指定
での for eachは、1回でだけですが、やはり必要なようです。
1つのメンバーしか持たないcollectionにあっても、兎に角、
for eachでやるしかないのかと思います。
逆に、セクッションの定義は何でしょうか?
大きな文書ファイルにて、第1章、第2章でしょうか?

3.ヘッダーの中でのFor eachは3回、回っています(フッターも)
この3回は、何なのでしょうか? ヘッダー(フッター)を3つの領域に分けることができるということでしょうか? 

4.テキストボックスに置いて、テキストロックが掛けられている場合、スキップするには、どうしたらよいでしょうか?

確かに、複数のテストボックスです。
a = ActiveDocument.Shapes.Count a=2とありました。
でも、何故か、2つめのテキストボックスでの
.Execute Replace:=wdReplaceAll
のところで、エラーとなってしまうのです。
テキストロックが掛けられているのだと思います(ロックの掛け方はまだ分かっていません)。先に進めるために、スキップしたいのです。

以上、よろしくお願い致します。

お礼日時:2015/11/07 11:03

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人はこんなQ&Aも見ています