Первоначальная проблема, которая привела меня к изучению VBA, заключается в следующем:
У вас есть таблица длиной до 10 000 строк (несколько сотен страниц) в документе Word. Таблица имеет заголовок в виде абзаца над первой строкой. Этот заголовок оформлен так, что он ссылается на оглавление (Style = "Caption"
). Таблица должна быть разбита на последнюю строку на каждой странице, а заголовок должен быть вставлен перед новой таблицей, но в другом стиле, который не связан с оглавлением (Style = "Caption Cont"
).
Первая страница будет выглядеть следующим образом:
Вторая страница будет выглядеть следующим образом:
Мое первое решение было относительно хаккейным и совсем не элегантным. Мне удалось собрать следующее решение, которое работает довольно хорошо. Однако первоначальный процесс определения номера строки, при которой таблица пересекает страницы, довольно медленный из-за использования Range.Information
. Мне интересно, есть ли более быстрый способ определить нижний ряд на странице.
Помещение документа в wdNormalView
сбрасывает около секунды на страницу, даже с Application.ScreenUpdating = False
...
Программа требует, чтобы курсор находился где-то внутри таблицы, что нормально а не функциональность, которую я буду sh удалять.
В настоящее время он обрабатывает около 120 страниц в минуту, причем большая часть времени тратится на определение строки, на которую нужно разделить (т. е. splitNum
). Я уверен, что это может быть намного быстрее с другим методом определения splitNum
.
Я НЕ МОГУ ДОБАВИТЬ ДОПОЛНИТЕЛЬНУЮ СТРОКУ В ТАБЛИЦУ ДЛЯ ЦЕЛЕЙ ИСПОЛЬЗОВАНИЯ «ПОВТОРНЫЕ СТРОКИ ЗАГОЛОВОК». Это будет нарушать правила, которые применяются в моей отрасли, и несоответствующий документ может иметь огромное значение для компании и будущего бизнеса
Код:
Sub tblSplit()
Dim timeCheck As Double
Application.ScreenUpdating = False
Application.ActiveWindow.View = wdNormalView
timeCheck = Time
On Error GoTo ErrH
Dim crossRef As Range, delRange As Range, tblR As Range, newTbl As Range
Dim tblNumField As Range, tblNum As String
Set tblNumField = Selection.Tables(1).Range
tblNumField.MoveStart wdParagraph, -1
tblNum = tblNumField.Words(2)
Set crossRef = Selection.Tables(1).Range
Set thisTbl = Selection.Tables(1).Rows(1).Range
Set tblR = Selection.Tables(1).Range
Вставить перекрестную ссылку к заголовку со стилем «Caption Cont»
crossRef.Move wdCharacter, -2
crossRef.InsertCrossReference ReferenceType:="Table", ReferenceKind:= _
wdOnlyCaptionText, ReferenceItem:=tblNum, InsertAsHyperlink:=True, _
IncludePosition:=False, SeparateNumbers:=False, SeparatorString:=" "
crossRef.Text = vbCr & " (Cont.)" & vbTab
crossRef.MoveStart wdCharacter, 1
crossRef.Style = "Caption Cont."
crossRef.Collapse wdCollapseStart
crossRef.InsertCrossReference ReferenceType:="Table", ReferenceKind:= _
wdOnlyLabelAndNumber, ReferenceItem:=tblNum, InsertAsHyperlink:=True, _
IncludePosition:=False, SeparateNumbers:=False, SeparatorString:=" "
crossRef.MoveEnd wdParagraph, 1
Удалить дублирующийся заголовок
Set delRange = crossRef.Duplicate
crossRef.MoveEnd wdParagraph, 1
crossRef.Copy
delRange.Text = vbNullString
Найти строку, в которой таблица занимает две страницы
Dim splitNum As Long, n As Long, i As Long, pageNum As Long
pageNum = tblR.Rows(1).Range.Information(wdActiveEndAdjustedPageNumber)
i = 15
Do
If tblR.Rows(i).Next.Range.Information(wdActiveEndAdjustedPageNumber) <> pageNum Then
splitNum = i
Exit Do
End If
i = i + 1
Loop Until i = 100 'arbitrary cap to prevent infinite loop
n = 1
Разделение и форматирование
Do
DoEvents
'Split and format
tblR.Tables(n).Split (splitNum)
tblR.Tables(n).Rows.Last.Borders(wdBorderBottom).LineStyle = wdLineStyleSingle
'Paste the stuff
Set newTbl = tblR.Tables(n + 1).Range
newTbl.Move wdParagraph, -2
newTbl.Paste
newTbl.MoveEnd wdParagraph, 1
'Clear excess
newTbl.Paragraphs.Last.Range.Text = vbNullString
'Next
n = n + 1
Loop Until tblR.Tables(n).Rows.Count < splitNum
Восстановление состояния, времени отчета, безопасного выхода и установка обработчика ошибок для отладки
Application.ActiveWindow.View = wdPrintView
Application.ScreenUpdating = True
MsgBox "Pages completed: " & n & vbCr & _
"Time (sec): " & DateDiff("s", timeCheck, Time) & vbCr & _
"Seconds per page: " & CDbl(DateDiff("s", timeCheck, Time)) / CDbl(n) & vbCr & _
"Pages per minute: " & n / DateDiff("s", timeCheck, Time) * 60
Exit Sub
ErrH:
Application.ScreenUpdating = True
Err.Raise Err.Number
Stop
End Sub