I am trying to duplicate a table row in Word, using VBA, without using the Selection object or the clipboard. That is, I want a new row that has the same content as an existing row.
To do this, I first create a new (empty) row, and loop through each cell in the source row and copy its contents into the corresponding cell in the target row.
To copy each cell, I get a Range
object that references the entire content of the source cell, and an equivalent Range
for the target cell, and then do this:
oToRange.FormattedText = oFromRange.FormattedText
This works well on Office 2003, and also works most of the time on Office 2010. However, I am having a real problem with one particular scenario. I have (greatly) simplified that scenario to demonstrate the core of the problem.
In the picture below, there are two cells in the outer (grey) 2R x 1C table. The second row is the row to be copied. The first row is the new row I created, and into which I want to copy the content of the second row.
You’ll notice that the second row contains a nested table.
When I run the code below in Word 2003, it works perfectly, and I get the following result:
But, in Word 2010, the same code produces this result:
As you can see, the cell content has been inserted before (and outside) the target table cell.
It’s worth mentioning that if I put something after the nested table, so that it’s no longer the last thing in the source cell, then this problem does not occur.
Here’s the full VBA code I’m using:
Dim oDoc As Word.Document
Set oDoc = ThisDocument
Dim oFromRange As Range
Set oFromRange = ThisDocument.Tables(1).Cell(2, 1).Range
oFromRange.End = oFromRange.End - 1
Dim oToRange As Range
Set oToRange = ThisDocument.Tables(1).Cell(1, 1).Range
oToRange.End = oToRange.End - 1
oToRange.FormattedText = oFromRange.FormattedText
NOTE: the adjustment to the end of the source and target ranges is necessary because Cell.Range
includes the end-of-cell marker, and I don’t want to copy that.
What can I do to persuade it to put the content inside the target cell (like Word 2003 does), rather than before it?
0 / 0 / 0 Регистрация: 13.11.2010 Сообщений: 19 |
|
1 |
|
08.03.2012, 00:26. Показов 10697. Ответов 5
Доброй ночи всем.
0 |
Sasha_Smirnov 5561 / 1367 / 150 Регистрация: 08.02.2009 Сообщений: 4,107 Записей в блоге: 30 |
||||||
08.03.2012, 08:42 |
2 |
|||||
Строки являются полями типа LINK, ссылающимися на закладки в таблице. Сам программировал часа два, что, конечно, дольше, чем 135 вырезаний по Ctrl-F3 и одна вставка по Ctrl-Shift-F3. Так что даю вам готовенькое, а сам метод просто немного проиллюстрировал, поскольку работа с полями тема другая. В приложенном архиве файл список фильмов.doc, можете попереключать там (по Alt-F9) вид поля/значения. Для установки закладок использован нижеследующий макрос.
Миниатюры
Вложения
1 |
0 / 0 / 0 Регистрация: 13.11.2010 Сообщений: 19 |
|
08.03.2012, 11:20 [ТС] |
3 |
Спасибо большое, Александр.
0 |
Sasha_Smirnov 5561 / 1367 / 150 Регистрация: 08.02.2009 Сообщений: 4,107 Записей в блоге: 30 |
||||
10.03.2012, 08:15 |
4 |
|||
Вам, очевидно, нужна такая вот (транспонированная) таблица (см. рисунок). Для одноразового транспонирования использовался следующий код.
(Объединение всех моих дёрганий в единый программный концепт мне пока не по силам.) Миниатюры
0 |
Sasha_Smirnov 5561 / 1367 / 150 Регистрация: 08.02.2009 Сообщений: 4,107 Записей в блоге: 30 |
||||||||||
11.03.2012, 00:06 |
5 |
|||||||||
РешениеСначала преобразовал в текст (1), затем подчистил — и обратно преобразовал в таблицу (2). В Word 97, 2000, 2003 инструменты на виду, в 2007 же и не пытался искать — шуршал макросами: (1)
(2)
Миниатюры
Вложения
0 |
5561 / 1367 / 150 Регистрация: 08.02.2009 Сообщений: 4,107 Записей в блоге: 30 |
|
11.03.2012, 00:47 |
6 |
Сначала преобразовал в текст (1), затем подчистил — и обратно преобразовал в таблицу (2). Перепутал макросы (1) и (2)!
0 |
I’m trying to use VBA to extract sentences in one Word document and put it into another Word document.
So for example, if we need to find the title of the organization, we follow the algorithm:
Search for «Title»
Do (Take) each character after «Title» and (stop) until «Address»
asked Jun 7, 2013 at 23:59
0
The following works but there may be a more efficient way of doing this:
Sub FindIt()
Dim blnFound As Boolean
Dim rng1 As Range
Dim rng2 As Range
Dim rngFound As Range
Dim strTheText As String
Application.ScreenUpdating = False
Selection.HomeKey wdStory
Selection.Find.Text = "Title"
blnFound = Selection.Find.Execute
If blnFound Then
Selection.MoveRight wdWord
Set rng1 = Selection.Range
Selection.Find.Text = "Address"
blnFound = Selection.Find.Execute
If blnFound Then
Set rng2 = Selection.Range
Set rngFound = ActiveDocument.Range(rng1.Start, rng2.Start)
strTheText = rngFound.Text
MsgBox strTheText
End If
End If
'move back to beginning
Selection.HomeKey wdStory
Application.ScreenUpdating = True
End Sub
You can switch between documents using Activate, preferably using object variables.
Microsoft MVP Jay Freedman kindly revised this for me to work without the Selection object, making it much neater.
Sub RevisedFindIt()
' Purpose: display the text between (but not including)
' the words "Title" and "Address" if they both appear.
Dim rng1 As Range
Dim rng2 As Range
Dim strTheText As String
Set rng1 = ActiveDocument.Range
If rng1.Find.Execute(FindText:="Title") Then
Set rng2 = ActiveDocument.Range(rng1.End, ActiveDocument.Range.End)
If rng2.Find.Execute(FindText:="Address") Then
strTheText = ActiveDocument.Range(rng1.End, rng2.Start).Text
MsgBox strTheText
End If
End If
End Sub
The only remaining requirement is to get this text into the other document. Something like:
Documents(2).Range.Text = strTheText
answered Jun 8, 2013 at 0:20
Andy GAndy G
19.1k5 gold badges49 silver badges69 bronze badges
2
This code will write to external file:
Sub RevisedFindIt_savetofile2 ()
' Purpose: display the text between (but not including)
' the words "Title" and "Address" if they both appear.
'This file will search current document only, the data in open word document.
Dim rng1 As Range
Dim rng2 As Range
Dim strTheText As String
Dim DestFileNum As Long
Dim sDestFile As String
sDestFile = "C:test-folderf12.txt" 'Location of external file
DestFileNum = FreeFile()
'A valid file number in the range 1 to 511,
'inclusive. Use the FreeFile function to obtain the next available file number.
Open sDestFile For Output As DestFileNum 'This opens new file with name DestFileNum
Set rng1 = ActiveDocument.Range
If rng1.Find.Execute(FindText:="Title") Then
Set rng2 = ActiveDocument.Range(rng1.End, ActiveDocument.Range.End)
If rng2.Find.Execute(FindText:="Address") Then
strTheText = ActiveDocument.Range(rng1.End, rng2.Start).Text
MsgBox strTheText 'writes string to a message box
Print #DestFileNum, strTheText 'Print # will write to external file with the text strTheText
End If
End If
Close #DestFileNum 'Close the destination file
End Sub
answered May 10, 2016 at 13:20
equalizerequalizer
1442 silver badges10 bronze badges
Both Excel and Word have a Range
object. Because you are in Excel VBA but are trying to reference the Word Range
object you need to qualify the variable declaration so that Excel knows you are using a Word Range object.
Dim rng1 As Word.Range
Dim rng2 As Word.Range
Credit to ChipsLetten for spotting this
answered Jul 30, 2015 at 12:28
You could (preferably) use the name of the other document, rather than the index (2):
Documents("OtherName").Range.Text = strTheText
However, this will change the text for the entire document, so you need to navigate to where you wish to insert the text.
It is far better, if possible, that there are pre-existing Bookmarks in the document (or template) that you can refer to:
Documents("OtherName").Bookmarks("bkSome").Range.Text = strTheText
Good luck.
answered Jun 8, 2013 at 21:00
Andy GAndy G
19.1k5 gold badges49 silver badges69 bronze badges
sevik111 Пользователь Сообщений: 22 |
#1 05.04.2019 15:34:25 Приветствую. Прошу помощи с макросом. Приходится работать с документами, в которых по пару тыс страниц. Вот и прошу помощи. Если возможно, помочь написать код, что бы автоматом копирование происходило, после того, как ворд найдет искомое слово в очередной строке (абзаце). Макрос, вполне может подойти и для подобных задач в Excel Макрос, что у меня получился
|
||
magistor8 Пользователь Сообщений: 184 |
#2 05.04.2019 15:46:10 Перебором абзацев:
|
||
sevik111 Пользователь Сообщений: 22 |
magistor8
а моя заготовка не подходит к даному сценарию |
sevik111 Пользователь Сообщений: 22 |
magistor8
либо я чего не так делаю, либо он находит только мама. При запросе другого слова находит только мама |
sevik111 Пользователь Сообщений: 22 |
magistor8
каждый новый запрос слова, нужно вписывать и сохранять в макрос? (помогите доразобраться) |
Андрей VG Пользователь Сообщений: 11878 Excel 2016, 365 |
#6 06.04.2019 10:22:34 Доброе время суток.
Вполне естественно. Где сборник ключевых слов, фраз?
Вы предоставили только слово мама, даже не указав, в каком виде и как это будет храниться. Каков был пример, таков получился и ответ. Updated
Изменено: Андрей VG — 06.04.2019 10:53:56 |
||||||
sevik111 Пользователь Сообщений: 22 |
Андрей VG
этот вариант немного легче предыдущего. Но все равно шаблонов придется не мало составить. Оптимальным вариантом, был бы через поиск (в том же ворде, ексель). Если не автоматом (перелопачивал весь документ), то хоть после каждого нажатия на «найти далее», что бы выделялся абзац и при запуске макроса, копировал в определенный документ (один и тот самый). Например: ищем нужные фразы в «новом, любом документе» и макрос копирует найденные совпадения в конкретный документ, скажем, под названием «Y» Мне для дальнейшей работы этого будет вполне достаточно. «в каком виде и как это будет храниться» — для меня достаточно в текстовом формате, в новом документе (для дальнейшей работы). Но только не каждая новая строка (абзац) в новом документе, а все найденные совпадения, в одном документе (я поэтому и назвал новый документ «Совпадения»). |
Андрей VG Пользователь Сообщений: 11878 Excel 2016, 365 |
#8 07.04.2019 07:10:47
Как определён этот документ, где расположен? Поменяйте в коде инициализацию destDoc — и получите желаемое.
Как определён этот список? Пока вижу картинку, в которой в поле ввода через точку с запятой указан такой список слов. Не вижу большой сложности написать код формы, который будет формировать шаблон для регулярного выражения. Для этого достаточно вместо
и в неё перед запуском предложенного метода формировать тот самый шаблон.
расшифруйте, и приложите пример, не понимаю этой фразы совсем. |
||||||||
sevik111 Пользователь Сообщений: 22 |
#9 07.04.2019 09:18:14
Список определяю я сам. Регулярных выражений нет. Если в одном документе мне нужно найти слово «мама», то в другом мне нужно найти «бабушку». (это примерные слова). Или в одном документе могу искать и 10, и 100 слов.
Он у меня расположен в корне диска D (D:Совпадения.dosx)
Предположим мне нужно найти словосочетание «иду гулять». В поиске я вбиваю искомую фразу «иду гулять» и нажимаю найти далее . Поиск находит фразу (совпадение, каких в документе может быть десятки) и с помощью макроса, мне нужно: 1 копирнуть абзац (с найденным словом, словосочетанием), 2 перейти на новую вкладку (по имени «Совпадения») и вставить найденный абзац, 3 возвращаюсь обратно в документ и ищу следующее совпадение, с той же искомой комбинацией «иду гулять» |
||||||
Андрей VG Пользователь Сообщений: 11878 Excel 2016, 365 |
Как-то так. Документ «Совпадения.docx» должен быть открыт. Прикрепленные файлы
|
sevik111 Пользователь Сообщений: 22 |
#11 07.04.2019 16:09:23 Андрей VG
простите, что не сразу смог объяснить то, что мне было нужно. Неплохое решение! Большое спасибо. Вопрос решен! |
Sub Макрос()
Dim табл As Table, rng As Range
‘1. Присваиваем имя «табл» выделенной таблице или таблице, в которой находится курсор.
Set табл = Selection.Tables(1)
‘2. Вставка разрыва страницы после таблицы.
‘1) Устанавливаем невидимый курсор после таблицы.
Set rng = табл.Range
rng.Collapse Direction:=wdCollapseEnd
‘2) Вставка разрыва.
rng.InsertBreak Type:=wdPageBreak
‘3. Копируем в буфер обмена строки 1 — 7.
табл.Rows(1).Select
Selection.MoveDown Unit:=wdLine, Count:=6, Extend:=True
Selection.Copy
‘4. Вставляем скопированное в начало следующей страницы.
rng.Paste
‘5. Присваиваем имя вставленной таблице.
Set табл = rng.Tables(1)
‘6. Очистка в таблице столбца 2.
табл.Columns(2).Select
Selection.Delete
End Sub
[свернуть]
Формулировка задачи:
Доброй ночи всем.
В прикрепленном документе информация о фильмах, мне нужно посмотреть всех актеров, которые играют в фильмах, перечисленных в документе, сидеть и перебирать 133 фильма думаю не рационально. Нельзя ли на VBA написать модуль копирования определенной строки? То есть со всех ячеек (информация о фильмах дана в виде таблицы) нужно скопировать строку «В главных ролях:…» и вставить в новый документ.
Код к задаче: «Копирование строк в MS Word»
textual
Sub toText() Selection.Tables.Item(1).ConvertToText Separator:=wdSeparateByParagraphs ', nestedtables:=False End Sub
Полезно ли:
6 голосов , оценка 3.833 из 5
Word VBA. Копировать строку без использования Clipboard
|
От: |
Enforcer |
|
Дата: | 27.12.07 11:41 | ||
Оценка: |
Доброго времени суток!
Пытаюсь написать собственный примитивный серверный генератор doc файлов по шаблонам. Генератор берет на вход шаблон, в котором отмечены места вставки полей из БД, а также отмечены строки таблицы, которые нужно размножить по количеству строчек таблицы БД со вставкой туда данных полей.
Основная загвоздка — как размножить строки некоей таблицы с сохранением форматирования, объединения ячеек и т.д.
Единственный способ который я нашел:
SomeRange.Rows.Select
Selection.Copy
Selection.Paste
Но этот способ использует буфер обмена (clipboard), который один на пользователя, генератор отчетов будет жить на сервере, обрабатывать параллельно сразу несколько запросов, поэтому всегда есть риск что между Copy и Paste какой-то другой процесс сумеет втиснуться и испортить буфер обмена. Фактически я этого добился, запустив 2 экземпляра приложения с пошаговой отладкой.
Метод Range.InsertAfter/InsertBefore не подходит, т.к. он принимает string, а не Range.
Конструкция вроде AnotherRange.InsertBefore(SomeRange.Text) приводит к тому что в одну ячейку таблицы пихается содержимое копируемой строчки с разделителями-новая строка заместо вставки новой строчки.
Может кто пытался реализовать схожую задачу, ну или просто смог продублировать содержимое некоторых строчек таблицы word один в один без использования буфера обмена?
Re: Word VBA. Копировать строку без использования Clipboard
|
От: |
ZAMUNDA |
для жалоб и предложений |
Дата: | 27.12.07 13:37 | ||
Оценка: |
Здравствуйте, Enforcer, Вы писали:
E>Доброго времени суток!
E>Метод Range.InsertAfter/InsertBefore не подходит, т.к. он принимает string, а не Range.
А почему тебе именно Range надо? У Range есть ещё Text, при этом, если использовать его то всё форматирование конечного Range сохраняется, т.е. ты просто на всех закладках в шаблоне форматирование нужное сделал, а потом переписываешь в них текст — я, в своём генераторе анкет так делал.
Правда у тебя там надо таблицы заполнять, ну тогда используй пользовательские стили, у того же Range есть свойство Style.
' Макрос в Application.Documents(2), т.е. ThisDocument есть Application.Documents(2).
' В обоих книгах я по закладке "test_bm" сделал.
With ThisDocument.Bookmarks("test_bm").Range
.Style = Application.Documents(1).Bookmarks("test_bm").Range.Style
.Text = Application.Documents(1).Bookmarks("test_bm").Range.Text
End With
Если открыты обе книги, то стили видны в обоих, после выполнения присваивания .Style, стиль из документа-шаблона скопируется в новый.
Наука изощряет ум; ученье вострит память.
(c) Козьма Прутков
Re[2]: Word VBA. Копировать строку без использования Clipboa
|
От: |
Enforcer |
|
Дата: | 27.12.07 14:05 | ||
Оценка: |
ZAM>Правда у тебя там надо таблицы заполнять, ну тогда используй пользовательские стили, у того же Range есть свойство Style.
У таблиц есть еще такая неприятная особенность, как свободный стиль рисования, когда ячейки произвольно объединяются вертикально и горизонтально со своей высотой и шириной. Просто скопировать стиль не получится.
Я пробовал прочитать разметку таблицы неким образом но каждый раз натыкался на засаду.
Если пробовать пройтись с использованием
1. foreach Row in Table.Rows (Col in Table.Columns)
выбрасывается исключение с текстом что то вроде «таблица не uniformed, по отдельным строчкам, столбцам ходить нельзя».
2. foreach Cell in Table.Cells такого не существует в природе, есть только Table.Cell(RowNum, CellNum),
3. а когда пытаешься пройтись
for row = 1 to Table.Rows.Count
for col = 1 to Table.Columns.Count
cell = Table.Cell(col, row)
next col
next row
для ячеек, которые объединены кидается исключение.
Можно конечно попробовать навернуть мегааналитический код, который запоминает структуру таблицы по тому кинулось ли исключение или нет, потом определить в каких ячейках какой текст сидит, потом всю эту мегаконструкцию воспроизводить самому, но мне казалось что гораздо более простой способ — скопировать все содержимое строки таблицы как есть и не заморачиваться с сохранением стилей, layout-ом таблицы и т.д.
При том что через Copy/Paste это делается на ура и как я писал единственный недостаток — использование clipboard-а.
Лирическое отступление:
Вообще я раньше довольно плотно работал с Excel VBA и там особо проблем не возникало. К слову там был нормальный метод что-то вроде
Range.InsertAfter(r as Range) т.е. можно было копировать любые области без использования clipboard.
Сейчас чем больше я пытаюсь испробовать подходов к решению элементарной задачи — наполнить word документ табличными данными с сохранением форматирования, заданного в dot шаблоне — тем больше меня разочаровывает объектная модель ворда. Уже 12 поколение, а возможности так и застряли где-то на 5-6.
Re: Word VBA. Копировать строку без использования Clipboard
|
От: |
PA |
|
Дата: | 27.12.07 22:39 | ||
Оценка: |
2 (1) |
Здравствуйте, Enforcer, Вы писали:
E>Может кто пытался реализовать схожую задачу, ну или просто смог продублировать содержимое некоторых строчек таблицы word один в один без использования буфера обмена?
Вот примерчик, показывающий как копировать строки и как работать со строками, содержащими объединённые ячейки:
Function getLastCellOfRow(CurrentCell As Cell) As Cell
Dim lastCell As Cell
Set lastCell = CurrentCell
Do
If lastCell.Next Is Nothing Then Exit Do
If lastCell.RowIndex < lastCell.Next.RowIndex Then Exit Do
Set lastCell = lastCell.Next
Loop
Set getLastCellOfRow = lastCell
End Function
Sub Test()
Dim doc As Document
Dim tbl As Table
Dim firstRowRange As Range
Dim i As Integer
Dim firstCell As Cell, lastCell As Cell
Set doc = ActiveDocument
Set tbl = doc.Tables(1)
Set firstCell = tbl.Cell(1, 1) 'первая ячейка первой строки
Set lastCell = getLastCellOfRow(firstCell) 'последняя ячейка первой строки
doc.Range(firstCell.Range.Start, lastCell.Range.End).Rows.Select 'выделяем первую строку
Set firstRowRange = Selection.FormattedText 'запомним содержимое первой строки
i = tbl.Rows.Count 'номер последней строки
Set firstCell = tbl.Cell(i, 1) 'первая ячейка последней строки
Set lastCell = getLastCellOfRow(firstCell) 'последняя ячейка последней строки
doc.Range(firstCell.Range.Start, lastCell.Range.End).FormattedText = firstRowRange 'вставляем копию первой строки
End Sub
Re[3]: Word VBA. Копировать строку без использования Clipboa
|
От: |
ZAMUNDA |
для жалоб и предложений |
Дата: | 28.12.07 08:58 | ||
Оценка: |
Здравствуйте, Enforcer, Вы писали:
ZAM>>Правда у тебя там надо таблицы заполнять, ну тогда используй пользовательские стили, у того же Range есть свойство Style.
E>У таблиц есть еще такая неприятная особенность, как свободный стиль рисования, когда ячейки произвольно объединяются вертикально и горизонтально со своей высотой и шириной. Просто скопировать стиль не получится.
Так ты используй таблицы без объединения ячеек. Заполни данными, а потом сделай объединения необходимые и прочие косметические махинации. Самый простой алгоритм в таком случае, это объединять смежные ячейки с одинаковыми данными в них.
E>Сейчас чем больше я пытаюсь испробовать подходов к решению элементарной задачи — наполнить word документ табличными данными с сохранением форматирования, заданного в dot шаблоне — тем больше меня разочаровывает объектная модель ворда. Уже 12 поколение, а возможности так и застряли где-то на 5-6.
Да увы и ах… но Word заточен не на работу с таблицами а на вёрстку документов. Поэтому работа с таблицами, а тем более, её автоматизация там сделаны «постольку-поскольку».
Наука изощряет ум; ученье вострит память.
(c) Козьма Прутков
Re[2]: Word VBA. Копировать строку без использования Clipboa
|
От: |
Enforcer |
|
Дата: | 28.12.07 13:42 | ||
Оценка: |
PA>Вот примерчик, показывающий как копировать строки и как работать со строками, содержащими объединённые ячейки:
Оно!
Спасибо огромное!
Если кому интересно как выглядит моя конкретная имплементация на C# с использованием word interop — стучитесь в аську 117446559, покажу
- Переместить
- Удалить
- Выделить ветку
Пока на собственное сообщение не было ответов, его можно удалить.