Word (VBA)

Word VBAに関するフォーラムです。
  • 解決済みのトピックにはコメントできません。
このトピックは解決済みです。
質問

 
(Windows 7 Professional : Word 2013)
storyranges.countが変わる
投稿日時: 18/07/30 13:23:11
投稿者: ストロベリー

Word文書の変更履歴を全て取得しようとして、StoryRangesを使っていますが、
StoryRanges.Countの数が途中で変わってしまいます。
対象のWordファイルにはヘッダー、フッター、図形があります。
変更履歴取得処理では変更履歴1つ取得したら、承諾するというのをやっていますが、
他にテキストを変更する処理はしていません。
 
StoryRanges.Countが変わる原因がわからなくて、何かヒントをいただけたらと思います。
よろしくお願いします。
 

  Dim storyRng As Word.Range
  
  For Each storyRng In wdDoc.StoryRanges
  
    Debug.Print "wdDoc.StoryRanges.Count=" & wdDoc.StoryRanges.Count
    
    ' 変更履歴取得処理

    ' 同じタイプのストーリーを取得
    While Not (storyRng.NextStoryRange Is Nothing)
    
      Set storyRng = storyRng.NextStoryRange
      
      ' 変更履歴取得処理
    
    Wend
    
  Next
  
  Set storyRng = Nothing


Debug.Printの結果
wdDoc.StoryRanges.Count=6
wdDoc.StoryRanges.Count=6
wdDoc.StoryRanges.Count=6
wdDoc.StoryRanges.Count=12
wdDoc.StoryRanges.Count=12
wdDoc.StoryRanges.Count=12
wdDoc.StoryRanges.Count=12
wdDoc.StoryRanges.Count=12
wdDoc.StoryRanges.Count=12
wdDoc.StoryRanges.Count=12
wdDoc.StoryRanges.Count=12
wdDoc.StoryRanges.Count=12

回答
投稿日時: 18/07/30 15:23:24
投稿者: sk

引用:
Word文書の変更履歴を全て取得しようとして、StoryRangesを使っていますが

変更履歴を参照するだけなら Revisions コレクションを
使用なされば充分であるように思いますが、
StoryRanges コレクションを使用されているのには
何か理由があるのでしょうか。
 
引用:
StoryRanges.Countの数が途中で変わってしまいます。
対象のWordファイルにはヘッダー、フッター、図形があります。
変更履歴取得処理では変更履歴1つ取得したら、承諾するというのをやっていますが、
他にテキストを変更する処理はしていません。

Count プロパティの値が増える前と増えた後での、
それぞれの(追加された)ストーリーの種類
( StoryType プロパティ)については、
既に確認されたのでしょうか。

投稿日時: 18/07/31 10:35:02
投稿者: ストロベリー

最初はDocument.Revisionsを使って、変更履歴を取得していましたが、
ヘッダーなどにある変更履歴が取れなくて、
それでStoryRangesから、Range.Revisionsを取ることにしました。
 
StoryRanges.Countが変わる前のStoryTypeは
wdMainTextStory
wdTextFrameStory
wdFootnoteSeparatorStory
wdFootnoteContinuationSeparatorStory
wdEndnoteSeparatorStory
wdEndnoteContinuationSeparatorStory
 
変わった後は
wdMainTextStory
wdTextFrameStory
wdEvenPagesHeaderStory
wdPrimaryHeaderStory
wdEvenPagesFooterStory
wdPrimaryFooterStory
wdFirstPageHeaderStory
wdFirstPageFooterStory
wdFootnoteSeparatorStory
wdFootnoteContinuationSeparatorStory
wdEndnoteSeparatorStory
wdEndnoteContinuationSeparatorStory
 
となっていて、ヘッダー、フッター関係のStoryが増えていました。

回答
投稿日時: 18/07/31 17:13:02
投稿者: sk

引用:
最初はDocument.Revisionsを使って、変更履歴を取得していましたが、
ヘッダーなどにある変更履歴が取れなくて、
それでStoryRangesから、Range.Revisionsを取ることにしました。

なるほど。
 
引用:
StoryRanges.Countが変わる前のStoryTypeは
wdMainTextStory
wdTextFrameStory
wdFootnoteSeparatorStory
wdFootnoteContinuationSeparatorStory
wdEndnoteSeparatorStory
wdEndnoteContinuationSeparatorStory

この場合、そのドキュメントに関しては「ヘッダー/フッターに対する
編集操作が全く行なわれたことがない」ということになるかと思われますが、
間違いないでしょうか。
 
引用:
変わった後は
wdMainTextStory
wdTextFrameStory
wdEvenPagesHeaderStory
wdPrimaryHeaderStory
wdEvenPagesFooterStory
wdPrimaryFooterStory
wdFirstPageHeaderStory
wdFirstPageFooterStory
wdFootnoteSeparatorStory
wdFootnoteContinuationSeparatorStory
wdEndnoteSeparatorStory
wdEndnoteContinuationSeparatorStory
  
となっていて、ヘッダー、フッター関係のStoryが増えていました。

今のところ考えられる可能性の 1 つとしては、「文書内のいずれかの
ヘッダーまたはフッター( HeaderFooter オブジェクト)の Range プロパティを
参照するようなコードが含まれている」ということが挙げられます。
 
例えば、以下のサンプルのようなコードを実行すると、
青字部分のステートメントが実行された後で、新たに
ストーリーが追加されるのを確認することが出来るはず。
 
(標準モジュール)
------------------------------------------------------------------------
Private Sub test1()
 
    Dim wdDoc As Word.Document
    Dim wdStoryRange As Word.Range
    Dim wdHeaderRange As Word.Range
     
    Set wdDoc = Documents.Add
    Debug.Print "[" & wdDoc & "]を新規作成しました。"
    Debug.Print "StoryRanges.Count = " & wdDoc.StoryRanges.Count & " 個"
     
    For Each wdStoryRange In wdDoc.StoryRanges
        Debug.Print vbTab & "StoryType: " & GetStoryTypeName(wdStoryRange.StoryType)
    Next
         
    'セクション1の主ヘッダーの領域を参照
    Set wdHeaderRange = wdDoc.Sections(1).Headers(wdHeaderFooterPrimary).Range
    Debug.Print "StoryRanges.Count = " & wdDoc.StoryRanges.Count & " 個"
    For Each wdStoryRange In wdDoc.StoryRanges
        Debug.Print vbTab & "StoryType: " & GetStoryTypeName(wdStoryRange.StoryType)
    Next
 
    wdDoc.Close False
 
    Set wdHeaderRange = Nothing
    Set wdStoryRange = Nothing
    Set wdDoc = Nothing
 
End Sub
 
'ストーリーの種類を日本語名で返す関数
Public Function GetStoryTypeName(StoryType As Word.WdStoryType) As String
 
    Dim strStoryType As String
 
    Select Case StoryType
        Case wdCommentsStory '値は 4
            strStoryType = "コメント ストーリー"
        Case wdEndnoteContinuationNoticeStory '値は 17
            strStoryType = "文末脚注継続時の注のストーリー"
        Case wdEndnoteContinuationSeparatorStory '値は 16
            strStoryType = "文末脚注継続時の境界線のストーリー"
        Case wdEndnoteSeparatorStory '値は 15
            strStoryType = "文末脚注の境界線のストーリー"
        Case wdEndnotesStory '値は 3
            strStoryType = "文末脚注のストーリー"
        Case wdEvenPagesFooterStory '値は 8
            strStoryType = "偶数ページのフッターのストーリー"
        Case wdEvenPagesHeaderStory '値は 6
            strStoryType = "偶数ページのヘッダーのストーリー"
        Case wdFirstPageFooterStory '値は 11
            strStoryType = "先頭ページのフッターのストーリー"
        Case wdFirstPageHeaderStory '値は 10
            strStoryType = "先頭ページのヘッダーのストーリー"
        Case wdFootnoteContinuationNoticeStory '値は 14
            strStoryType = "脚注継続時の注のストーリー"
        Case wdFootnoteContinuationSeparatorStory '値は 13
            strStoryType = "脚注継続時の境界線のストーリー"
        Case wdFootnoteSeparatorStory '値は 12
            strStoryType = "脚注の境界線のストーリー"
        Case wdFootnotesStory '値は 2
            strStoryType = "脚注のストーリー"
        Case wdMainTextStory '値は 1
            strStoryType = "メイン テキスト ストーリー"
        Case wdPrimaryFooterStory '値は 9
            strStoryType = "主フッターのストーリー"
        Case wdPrimaryHeaderStory '値は 7
            strStoryType = "主ヘッダーのストーリー"
        Case wdTextFrameStory '値は 5
            strStoryType = "レイアウト枠のストーリー"
        Case Else
            strStoryType = ""
    End Select
     
    GetStoryTypeName = strStoryType
 
End Function
------------------------------------------------------------------------

投稿日時: 18/08/01 12:34:16
投稿者: ストロベリー

変更履歴を取得する時は、

StoryRangeから変更履歴を取得
 ↓
StoryRangeにshapeRangeがあって、shape.TextFrame.HasText = Trueだったら、
shape.TextFrame.TextRangeから変更履歴を取得

ヘッダー、フッターの Range プロパティを見には行ってないのですが。。。
 
skさんのサンプルはヘッダー、フッターに文字を入れていないのに、
引用:

Set wdHeaderRange = wdDoc.Sections(1).Headers(wdHeaderFooterPrimary).Range

だけで、StoryRanges.Countが変わるのはすごく不思議に思います。
StoryRangesは対象文書で使われているところだけ、出てくるものではないでしょうか??
ヘッダーにテキストがあったら、ヘッダーのStory、フッターがあったらフッターのStoryみたいな。。。

回答
投稿日時: 18/08/01 16:50:37
投稿者: sk

引用:
skさんのサンプルはヘッダー、フッターに文字を入れていないのに、
引用:

Set wdHeaderRange = wdDoc.Sections(1).Headers(wdHeaderFooterPrimary).Range

だけで、StoryRanges.Countが変わるのはすごく不思議に思います。
StoryRangesは対象文書で使われているところだけ、出てくるものではないでしょうか??
ヘッダーにテキストがあったら、ヘッダーのStory、フッターがあったらフッターのStoryみたいな。。。

この例での肝心なポイントは、
 
・何らかのオブジェクト/プロパティをただ参照するだけで
 ストーリーが追加されることがある。
 
・私が示したサンプルと同様の結果をもたらすコードが
 他にも存在する可能性がある。
 
・つまり、どのストーリーが何の拍子で追加されるかは
 実際に試してみない限りは分からない
 
というところにあります。
 
引用:
Set wdHeaderRange = wdDoc.Sections(1).Headers(wdHeaderFooterPrimary).Range

例えば、前述のサンプルにおける上記のステートメントを
 
-------------------------------------------------------------------------
 
Debug.Print wdDoc.Sections(1).Headers(wdHeaderFooterPrimary).Shapes.Count
 
-------------------------------------------------------------------------
 
のように書き換えて実行すると、ヘッダー/フッター関連のストーリーは
追加されませんが、脚注/文末脚注の境界線関連のストーリーが追加されます。
(前者ではストーリーの数が 11、後者では 5 になるはず)
 
引用:
変更履歴を取得する時は、
StoryRangeから変更履歴を取得
 ↓
StoryRangeにshapeRangeがあって、shape.TextFrame.HasText = Trueだったら、
shape.TextFrame.TextRangeから変更履歴を取得

ヘッダー、フッターの Range プロパティを見には行ってないのですが。。。

「ヘッダーの領域をただ参照する」「ヘッダー内の図形の個数を取得する」
といった、一見何の関わりもなさそうなコードを実行しただけでも
こういった結果になるわけですから、まずは実際のコードにおいて
直接の原因となっているステートメントを特定するところから
始めてみる必要があると思います。
(少なくとも、最初に例示されたコードだけでは
現象が再現されませんでした)
 
引用:
wdDoc.StoryRanges.Count

例えば、上記の式をウォッチウィンドウに追加した上、
ステップイン実行をしながら Count プロパティの値の
遷移状況を検証するといった作業を行なってみては
いかがでしょうか。

投稿日時: 18/08/02 10:00:35
投稿者: ストロベリー

skさん、詳しく説明していただいて、ありがとうございます。
 
step実行でStoryRanges.countが変わるところを見ようとしたら、
なぜか最初から最後までStoryRanges.count=12のままで、数の変化がありませんでした。
やったことは実行する前にStoryRanges.countをウォッチウィンドウに追加しただけで、
プログラム、対象のWord文章に対して、一切変更をしていません。
(私のWordがおかしい??)
 
Word文書のテキストを漏れが無く全て見たい時は、StoryRangesを回せば全部見れると思っていたのですが、
今回のように、何かをやっていて、Storyが増えていたので、その何かをやっていなかったら、
全てのテキストが見れないことになります。
 
StoryRanges以外で全てのテキストを見る方法があったりしますか?

回答
投稿日時: 18/08/02 13:26:19
投稿者: んなっと

Sub test1()
  Dim rngStory As Range
  Dim lngJunk As Long
  Debug.Print "数1"; ActiveDocument.StoryRanges.Count
  For Each rngStory In ActiveDocument.StoryRanges
    Do
      Debug.Print rngStory.StoryType; Left(Replace(rngStory.Text, vbCr, vbNullString), 5)
      Set rngStory = rngStory.NextStoryRange
    Loop Until rngStory Is Nothing
  Next
  Debug.Print "数3"; ActiveDocument.StoryRanges.Count
End Sub
 
数1 10
 1 あああ
 2  いい
 5 bbbb
 5 aaaa
 7
 8
 9 1
 12 
 13 
 15 
 16 
数3 10
 
この文書の場合、6,10,11が飛んでいますね。
空っぽのStoryRangeなのでStoryRanges.Countに含まれないようです。省エネですね。
 
 
 
 
飛ばないようにするには、なんらかの呪文を唱えてからループします。呪文はいろいろあるようです。
 
Sub test2()
  Dim rngStory As Range
  Dim lngJunk As Long
  Debug.Print "数1"; ActiveDocument.StoryRanges.Count
  lngJunk = ActiveDocument.Sections(1).Headers(1).Range.StoryType
  Debug.Print "数2"; ActiveDocument.StoryRanges.Count
  For Each rngStory In ActiveDocument.StoryRanges
    Do
      Debug.Print rngStory.StoryType; Left(Replace(rngStory.Text, vbCr, vbNullString), 5)
      Set rngStory = rngStory.NextStoryRange
    Loop Until rngStory Is Nothing
  Next
  Debug.Print "数3"; ActiveDocument.StoryRanges.Count
End Sub
 
数1 10
数2 13
 1 あああ
 2  いい
 5 bbbb
 5 aaaa
 6
 7
 8
 9 1
 10
 11
 12 
 13 
 15 
 16 
数3 13
 
今度は6,10,11も飛ばさずにループ処理していますね。
一度でも呪文を唱えたら、以後その文書はStoryRanges.Countがずっと増加したままです。
 
 
さらに、例えば「ヘッダーに、テキストボックスだけを挿入したのだがスキップされて置換の対象にならない」
などの問題がでてきたときは、test2を改良したtest3で対処することになるそうです。
 
Sub test3()
  Dim rngStory As Range
  Dim lngJunk As Long
  Dim oShp As Shape
  Debug.Print "数1"; ActiveDocument.StoryRanges.Count
  lngJunk = ActiveDocument.Sections(1).Headers(1).Range.StoryType
  Debug.Print "数2"; ActiveDocument.StoryRanges.Count
  For Each rngStory In ActiveDocument.StoryRanges
    Do
      Debug.Print rngStory.StoryType; Left(Replace(rngStory.Text, vbCr, vbNullString), 5)
      On Error Resume Next
      Select Case rngStory.StoryType
        Case 6 To 11
          If rngStory.ShapeRange.Count > 0 Then
            For Each oShp In rngStory.ShapeRange
              If oShp.TextFrame.HasText Then
                Debug.Print rngStory.StoryType; Left(Replace(oShp.TextFrame.TextRange.Text, vbCr, vbNullString), 5)
              End If
            Next
          End If
      End Select
      On Error GoTo 0
      Set rngStory = rngStory.NextStoryRange
    Loop Until rngStory Is Nothing
  Next
  Debug.Print "数3"; ActiveDocument.StoryRanges.Count
End Sub
 
数1 10
数2 13
 1 あああ
 2  いい
 5 bbbb
 5 aaaa
 6
 7   
 7 cccc ←空のヘッダーに挿入したテキストボックスも処理している
 8
 9 1
 10
 11
 12 
 13 
 15 
 16 
数3 13

投稿日時: 18/08/02 14:26:25
投稿者: ストロベリー

んなっとさん、サンプルを示していただいて、ありがとうございます。
 

lngJunk = ActiveDocument.Sections(1).Headers(1).Range.StoryType

これを実行することによって、ヘッダー、フッター関係のStoryが増えましたが、
他のStoryに関しても、なんらかの呪文みたいのをしないと、出てこない可能性があるでしょうか?
 
 

回答
投稿日時: 18/08/02 15:35:37
投稿者: んなっと

StoryRanges.Countの数の増加は問題の本質ではありませんよね。
そこを騒いでも無意味です。
質問の趣旨がずれているような気がしたので、無視していました。
「文書の多くの場所の●●を調べたい」というのが目的のはずです。

回答
投稿日時: 18/08/02 15:37:27
投稿者: んなっと

大した問題ではないので、スレッドを閉じましょうね。

回答
投稿日時: 18/08/02 17:10:09
投稿者: sk

引用:
step実行でStoryRanges.countが変わるところを見ようとしたら、
なぜか最初から最後までStoryRanges.count=12のままで、数の変化がありませんでした。
やったことは実行する前にStoryRanges.countをウォッチウィンドウに追加しただけで、
プログラム、対象のWord文章に対して、一切変更をしていません。
(私のWordがおかしい??)

例えば、検証対象となったドキュメントのストーリーの数が
既に 12 個になった状態で(テキスト編集自体は行なわれずに)
上書き保存されてしまった可能性が疑われます。
 
引用:
Word文書のテキストを漏れが無く全て見たい時は、
StoryRangesを回せば全部見れると思っていたのですが、
今回のように、何かをやっていて、Storyが増えていたので、
その何かをやっていなかったら、全てのテキストが見れないことになります。

文書内の全てのテキストを参照するのに StoryRanges コレクションを
利用するということ自体には、特に問題はないと思います。
(少なくとも、何らかのテキストが含まれている文書内の領域が
どのストーリーにも属さない、というのは考えにくいでしょう)
 
今回の現象に関して言えば、何らかの原因によって
ヘッダーやフッターのストーリーが追加されてはいるようですが、
その領域内にある文字はキャリッジリターンだけであり、
それはヘッダー/フッターにおけるデフォルトの状態です
実質的には、何のテキストもないに等しい)。
そのままならば「追加」の変更履歴が追加されることもないので、
大した実害はないと思います。
 
引用:
StoryRanges以外で全てのテキストを見る方法があったりしますか?

「ある単一のコレクション/プロパティを介して」という意味で
おっしゃっているのならば、恐らくないと思います。
 
ヘッダー/フッター、レイアウト枠、脚注、文末脚注に当たる
それぞれのオブジェクトのメンバから、Revisions なり Range なりの
コレクション/オブジェクト/プロパティを参照するような
形になるでしょう。

投稿日時: 18/08/03 09:29:39
投稿者: ストロベリー

skさん、回答していただいて、ありがとうございます。
もう一回自分のプログラムを見直してみます。
 
ありがとうございました。