英文:
Find and copy paragraphs from Word
问题
我有一个包含编号问题列表的Word文档,例如:
-
问题1
问题1的内容...
一些问题1的图片 -
问题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.
-
Question 1
Question 1 stuff....
some question 1 pictures -
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)
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
' (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
' (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 > 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 ' 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
' (...)
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 'use here the sheet you need
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") 'it finds the Word open session
Set objDoc = objWord.Documents("Test Word VBA.docm")
If objWord Is Nothing Then
Set objWord = CreateObject("Word.Application") '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 'the found first paragraph 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 'the second question paragraph range
End If
End With
End With
Else
Set rng2 = objDoc.Range
End If
'extend the first found paragraph range, up to the next question:
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 "Ready..."
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 = "1:10" 'here questions from 1 to 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, 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...
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论