查找并复制Word文档中的段落。

huangapple go评论51阅读模式
英文:

Find and copy paragraphs from Word

问题

我有一个包含编号问题列表的Word文档,例如:

  1. 问题1
    问题1的内容...
    一些问题1的图片

  2. 问题2
    问题2的内容...

等等

我试图编写一个Excel程序,它可以打开这个Word文档并复制各个问题及其图片。

我的目前代码如下:

Set objWord = CreateObject("Word.Application")
objWord.Visible = True

Set objDoc = objWord.Documents.Open("MyFileName")

Set objRange = objDoc.Range

objRange.Copy

shquestions.Range("A1").PasteSpecial

objWord.Quit SaveChanges:=False
Set objWord = Nothing

这段代码可以复制整个Word文档,并以我想要的方式粘贴(作为图像,包括来自Word文档的图片)。

但是,我不知道如何让代码选择问题1并复制粘贴它,然后选择问题2并复制粘贴它。

问题总是有编号,所以我可以使用编号来识别下一个问题,但我不知道如何将我的objRange 设置为Word文档中的特定区域。

以下是Word文档的示例外观(我删除了问题文本,因为不是我的内容,所以不能分享)。

我希望的是,我可以根据编号来定义范围(因此从顶部复制到2号前的行,等等)。

但到目前为止,我只能找出如何定义第一个和最后一个范围。

objDoc.Paragraphs.First.Range
objDoc.Paragraphs.Last.Range

请帮助我找出如何根据问题的编号来选择和复制它们。

英文:

I have a word document with a list of questions that are numbered
e.g.

  1. Question 1
    Question 1 stuff....
    some question 1 pictures

  2. Question 2
    Quest 2 stuff....

etc

I'm trying to write an excel program that will open the word document and copy the various questions and their images.

My code so far is:

Set objWord = CreateObject("Word.Application")
objWord.Visible = True

Set objDoc = objWord.Documents.Open("MyFileName")

Set objRange = objDoc.Range

objRange.Copy

shquestions.Range("A1").PasteSpecial
        
objWord.Quit SaveChanges:=False
Set objWord = Nothing

Which works fine at copying the entire word document, and pasting it exactly how I want (as an image, with the images from word document included)

However I can't work out how to get the code to select question 1 and copy and paste it, then question 2 and copy and paste it.

Questions are always numbered so I can use that to identify the next question, but I don't know how to set my objRange to a specific area in the word document

This is a sample of how the word document looks (I took out the questions text, as doesn't belong to me so I can't really share)

查找并复制Word文档中的段落。

What I was hoping was that I could define the range based on the numbering (so copy from the top to the line just before number 2. etc

But so far all I can figure out is how to define the first and last range

objDoc.Paragraphs.First.Range
objDoc.Paragraphs.Last.Range

答案1

得分: 1

以下是翻译好的内容:

你可以使用 ListParagraphs 访问 Word 文档中的列表元素。所以最基本的代码如下:

With ThisDocument
    .Range.ListParagraphs(1).Range.Copy
    '(现在可以执行任何你想要的操作)
End With

或者,使用循环的方式:

Dim i As Long
For i = 1 to .Range.ListParagraphs(i).Count
    .Range.ListParagraphs(i).Range.Copy
    '(同样:现在可以执行任何你想要的操作)
Next

现在,这有两个问题:

(1) 这只会复制带有编号的段落。你的数据看起来每个问题可能包含多个段落,所以我们需要寻找下一个问题的开头。

(2) ListParagraphs 列出了所有包含编号的段落。如果你的问题 1 包含子列表(1.1、1.2...),那些子列表的段落也会出现在 ListParagraphs 集合中。

下面的函数将搜索特定级别的列表编号,并返回包含所有文本的范围,直到下一个带有编号的段落。

Function GetListRange(doc As Document, listLevel As Long, listValue As Variant) As Range
    Dim rStart As Range, rEnd As Range, i As Long
    For i = 1 To doc.ListParagraphs.Count
        Dim p As Paragraph
        Set p = doc.ListParagraphs(i)
        With p.Range.ListFormat
            If .ListLevelNumber = listLevel And .listValue = listValue Then
                Set rStart = p.Range
            End If
            
            If Not rStart Is Nothing _
            And ((.ListLevelNumber = listLevel And .listValue > listValue) _
             Or .ListLevelNumber < listLevel) Then
                Set rEnd = p.Range
                Exit For
            End If
        End With
    Next i

    If rStart Is Nothing Then Exit Function   ' ListValue not present
    
    If rEnd Is Nothing Then ' 最后一个列表项,复制直到文档的末尾
        Set GetListRange = doc.Range(rStart.Start, doc.Range.End)
    Else
        Set GetListRange = doc.Range(rStart.Start, rEnd.Start)
    End If
End Function

现在你可以循环遍历所有的“问题”:

Dim questionNr as Long, questionRange as Range
questionNr = 0
Do While True
    questionNr = questionNr + 1
    Set questionRange = GetListRange(ActiveDocument, 1, questionNr)
    If questionRange Is Nothing Then Exit Loop

    questionRange.Copy
    '(...)
Loop

希望这些翻译对你有帮助。

英文:

You can access the list elements in a word document with ListParagraphs. So the most basic code would be

With ThisDocument
    .Range.ListParagraphs(1).Range.Copy
    &#39; (Do whatever you want to do now)
End With

Or, as Loop:

Dim i As Long
For i = 1 to .Range.ListParagraphs(i).Count
    .Range.ListParagraphs(i).Range.Copy
    &#39; (Again: Do whatever you want to do now)
Next

Now, this has 2 issues:

(1) That would only copy the paragraph that is numbered. Your data looks as if there are many paragraphs per question, so we have to look for the begin of the next question.

(2) ListParagraphs lists all paragraphs that contain numbering. If your question 1 contains sublists (1.1, 1.2...), those sublist paragraphs would also be within the ListParagraphs collection.

The following function will search for a List number on a certain level and return the range containing all text until the paragraph with the next number.

Function GetListRange(doc As Document, listLevel As Long, listValue As Variant) As Range
    Dim rStart As Range, rEnd As Range, i As Long
    For i = 1 To doc.ListParagraphs.Count
        Dim p As Paragraph
        Set p = doc.ListParagraphs(i)
        With p.Range.ListFormat
            If .ListLevelNumber = listLevel And .listValue = listValue Then
                Set rStart = p.Range
            End If
            
            If Not rStart Is Nothing _
            And ((.ListLevelNumber = listLevel And .listValue &gt; listValue) _
             Or .ListLevelNumber &lt; listLevel) Then
                Set rEnd = p.Range
                Exit For
            End If
        End With
    Next i

    If rStart Is Nothing Then Exit Function   &#39; ListValue not present
    
    If rEnd Is Nothing Then &#39; Last entry in List, copy till the end of document
        Set GetListRange = doc.Range(rStart.Start, doc.Range.End)
    Else
        Set GetListRange = doc.Range(rStart.Start, rEnd.Start)
    End If
End Function

Now you can loop over all "questions" with

Dim questionNr as Long, questionRange as Range
questionNr = 0
Do While True
    questionNr = questionNr + 1
    Set questionRange = GetListRange(ActiveDocument, 1, questionNr)
    If questionRange Is Nothing Then Exit Loop

    questionRange.Copy
    &#39; (...)
Loop

答案2

得分: 1

请尝试下一个函数。它假设在两个以“Question #”开头的连续段落之间,还有其他段落(blah blah部分)需要复制,图片也必须保留在相应的范围内。请确保在使用的常量中使用您的真实文档全名:

Sub CopyQuestionsfromFromWord(Q1 As String, Q2 As String, Optional boolLast As Boolean = False)
 Dim objWord As Word.Application, objDoc As Word.Document, objRange As Word.Range
 Dim rng1 As Word.Range, rng2 As Word.Range
 Dim shquestions As Worksheet, lastR As Long
 
 Set shquestions = ActiveSheet '在此处使用您需要的工作表
 lastR = shquestions.Range("A" & shquestions.Rows.Count).End(xlUp).Row + 2
 
 Const MyFileName As String = "C:\Teste VBA Excel\Word VBA\Test Word VBA.docm"
 
 On Error Resume Next
  Set objWord = GetObject(, "Word.Application") '它会找到打开的 Word 会话
  Set objDoc = objWord.Documents("Test Word VBA.docm")
  If objWord Is Nothing Then
    Set objWord = CreateObject("Word.Application") '如果找不到,则打开一个新的
    Set objDoc = objWord.Documents.Open(MyFileName)
  End If
 On Error Resume Next: Err.Clear
 
 objWord.Visible = True
 
 Set objRange = objDoc.Content
 With objRange
    With .Find
        .Text = Q1
        If .Execute Then
            Set rng1 = objRange.Paragraphs(1).Range '找到的第一个段落范围
        End If
    End With
 End With
 
 Set objRange = objDoc.Content
 If Q2 <> "" Then
    With objRange
       With .Find
           .Text = Q2
            If .Execute Then
               Set rng2 = objRange.Paragraphs(1).Range '第二个问题段落范围
           End If
       End With
    End With
 Else
   Set rng2 = objDoc.Range
 End If
 '扩展第一个找到的段落范围,直到下一个问题:
  rng1.SetRange Start:=rng1.Start, End:=IIf(Q2 <> "", rng2.Start, rng2.End)
  rng1.Copy
  
  shquestions.Range("A" & lastR).Select
  shquestions.PasteSpecial Format:="HTML", Link:=False, DisplayAsIcon:=False
 
 If boolLast Then
    If Not Q2 = "" Then
        CopyQuestionsfromFromWord Q2, "", True
    Else
        objDoc.Close SaveChanges:=False
        objWord.Quit
        MsgBox "准备就绪..."
    End If
 End If
End Sub

它可以以下列方式使用。您只需要在nrQ常量中写入问题的区间:

Sub testCopyQuestionsfromFromWord()
  Dim nrQ As String: nrQ = "1:10" '这里是从1到10的问题
  Dim arrQ: arrQ = Application.Evaluate("Transpose(Row(" & nrQ & "))")
  arrQ = Split("Question " & Join(arrQ, "|Question "), "|")
  Dim i As Long
  For i = 0 To UBound(arrQ) - 1
    If i = UBound(arrQ) - 1 Then
        CopyQuestionsfromFromWord CStr(arrQ(i)), CStr(arrQ(i + 1)), True
    Else
        CopyQuestionsfromFromWord CStr(arrQ(i)), CStr(arrQ(i + 1))
    End If
  Next i
End Sub

在测试后,请提供一些反馈。

现在,上述解决方案,在找到最后一个问题后,它会从该段落返回到文件的末尾,假设在此最后一个问题之后没有其他内容。但是,如果存在其他内容,您应该在最后一个问题之后放置一种标记,比如说“问题结束”,我将调整代码以返回到该标记...

英文:

Please, try the next function. It assumes that between two consecutive paragraphs starting with "Question #" other paragraphs (the blah, blah part) which must be copied and the picture staying on the respective range, too. Take care to use your real document full name in the used Constant:

Sub CopyQuestionsfromFromWord(Q1 As String, Q2 As String, Optional boolLast As Boolean = False)
 Dim objWord As Word.Application, objDoc As Word.Document, objRange As Word.Range
 Dim rng1 As Word.Range, rng2 As Word.Range
 Dim shquestions As Worksheet, lastR As Long
 
 Set shquestions = ActiveSheet &#39;use here the sheet you need
 lastR = shquestions.Range(&quot;A&quot; &amp; shquestions.rows.count).End(xlUp).row + 2
 
 Const MyFileName As String = &quot;C:\Teste VBA Excel\Word VBA\Test Word VBA.docm&quot;
 
 On Error Resume Next
  Set objWord = GetObject(, &quot;Word.Application&quot;) &#39;it finds the Word open session
  Set objDoc = objWord.Documents(&quot;Test Word VBA.docm&quot;)
  If objWord Is Nothing Then
    Set objWord = CreateObject(&quot;Word.Application&quot;) &#39;if not found open a new one
    Set objDoc = objWord.Documents.Open(MyFileName)
  End If
 On Error Resume Next: err.Clear
 
 objWord.Visible = True
 
 Set objRange = objDoc.content
 With objRange
    With .Find
        .text = Q1
        If .Execute Then
            Set rng1 = objRange.Paragraphs(1).Range &#39;the found first paragraph range
        End If
    End With
 End With
 
 Set objRange = objDoc.content
 If Q2 &lt;&gt; &quot;&quot; Then
    With objRange
       With .Find
           .text = Q2
            If .Execute Then
               Set rng2 = objRange.Paragraphs(1).Range &#39;the second question paragraph range
           End If
       End With
    End With
 Else
   Set rng2 = objDoc.Range
 End If
 &#39;extend the first found paragraph range, up to the next question:
  rng1.SetRange start:=rng1.start, End:=IIf(Q2 &lt;&gt; &quot;&quot;, rng2.start, rng2.End)
  rng1.Copy
  
  shquestions.Range(&quot;A&quot; &amp; lastR).Select
  shquestions.PasteSpecial Format:=&quot;HTML&quot;, link:=False, DisplayAsIcon:=False
 
 If boolLast Then
    If Not Q2 = &quot;&quot; Then
        CopyQuestionsfromFromWord Q2, &quot;&quot;, True
    Else
        objDoc.Close SaveChanges:=False
        objWord.Quit
        MsgBox &quot;Ready...&quot;
    End If
 End If
End Sub

It can be used in the next way. You should only write in nrQ constant the Questions interval:

Sub testCopyQuestionsfromFromWord()
  Dim nrQ As String: nrQ = &quot;1:10&quot; &#39;here questions from 1 to 10
  Dim arrQ: arrQ = Application.Evaluate(&quot;Transpose(Row(&quot; &amp; nrQ &amp; &quot;))&quot;)
  arrQ = Split(&quot;Question &quot; &amp; Join(arrQ, &quot;|Question &quot;), &quot;|&quot;)
  Dim i As Long
  For i = 0 To UBound(arrQ) - 1
    If i = UBound(arrQ) - 1 Then
        CopyQuestionsfromFromWord CStr(arrQ(i)), CStr(arrQ(i + 1)), True
    Else
        CopyQuestionsfromFromWord CStr(arrQ(i)), CStr(arrQ(i + 1))
    End If
  Next i
End Sub

Please, send some feedback after testing it.

Now, the above solution, after the last question found, it return from that paragraph to the end of the file, assuming that nothin else exist after this last question. But, if it exists, you should place a kind of marker, let us say "End of Questions" after the last one and I will adapt the code to return up to it...

huangapple
  • 本文由 发表于 2023年7月17日 17:01:12
  • 转载请务必保留本文链接:https://go.coder-hub.com/76702896.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定