title | description | ms.date | ms.topic | dev_langs | helpviewer_keywords | author | ms.author | manager | ms.technology | ms.workload | |||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Find and replace text in documents programmatically |
Learn how you can use Visual Studio to programmatically search for and replace text in a Microsoft Word document. |
02/02/2017 |
how-to |
|
|
John-Hart |
johnhart |
jmartens |
office-development |
office |
How to: Programmatically search for and replace text in documents
[!INCLUDE Visual Studio]
The xref:Microsoft.Office.Interop.Word.Find object is a member of both the xref:Microsoft.Office.Interop.Word.Selection and the xref:Microsoft.Office.Interop.Word.Range objects, and you can use either one to search for text in Microsoft Office Word documents. The replace command is an extension of the find command.
Use a xref:Microsoft.Office.Interop.Word.Find object to loop through a Microsoft Office Word document and search for specific text, formatting, or style, and use the xref:Microsoft.Office.Interop.Word.Find.Replacement%2A property to replace any of the items found.
[!INCLUDEappliesto_wdalldocapp]
Use a Selection object
When you use a xref:Microsoft.Office.Interop.Word.Selection object to find text, any search criteria you specify are applied only against currently selected text. If the xref:Microsoft.Office.Interop.Word.Selection is an insertion point, then the document is searched. When the item is found that matches the search criteria, it is automatically selected.
It is important to note that the xref:Microsoft.Office.Interop.Word.Find criteria are cumulative, which means that criteria are added to previous search criteria. Clear formatting from previous searches by using the xref:Microsoft.Office.Interop.Word.Find.ClearFormatting%2A method prior to the search.
To find text using a Selection object
-
Assign a search string to a variable.
C#
:::code language=»csharp» source=»../vsto/codesnippet/CSharp/Trin_VstcoreWordAutomationCS/ThisDocument.cs» id=»Snippet68″:::
VB
:::code language=»vb» source=»../vsto/codesnippet/VisualBasic/Trin_VstcoreWordAutomationVB/ThisDocument.vb» id=»Snippet68″:::
-
Clear formatting from previous searches.
C#
:::code language=»csharp» source=»../vsto/codesnippet/CSharp/Trin_VstcoreWordAutomationCS/ThisDocument.cs» id=»Snippet69″:::
VB
:::code language=»vb» source=»../vsto/codesnippet/VisualBasic/Trin_VstcoreWordAutomationVB/ThisDocument.vb» id=»Snippet69″:::
-
Execute the search and display a message box with the results.
C#
:::code language=»csharp» source=»../vsto/codesnippet/CSharp/Trin_VstcoreWordAutomationCS/ThisDocument.cs» id=»Snippet70″:::
VB
:::code language=»vb» source=»../vsto/codesnippet/VisualBasic/Trin_VstcoreWordAutomationVB/ThisDocument.vb» id=»Snippet70″:::
The following example shows the complete method.
C#
:::code language=»csharp» source=»../vsto/codesnippet/CSharp/Trin_VstcoreWordAutomationCS/ThisDocument.cs» id=»Snippet67″:::
VB
:::code language=»vb» source=»../vsto/codesnippet/VisualBasic/Trin_VstcoreWordAutomationVB/ThisDocument.vb» id=»Snippet67″:::
Use a Range object
Using a xref:Microsoft.Office.Interop.Word.Range object enables you to search for text without displaying anything in the user interface. The xref:Microsoft.Office.Interop.Word.Find object returns True if text is found that matches the search criteria, and False if it does not. It also redefines the xref:Microsoft.Office.Interop.Word.Range object to match the search criteria if the text is found.
To find text using a Range object
-
Define a xref:Microsoft.Office.Interop.Word.Range object that consists of the second paragraph in the document.
The following code example can be used in a document-level customization.
C#
:::code language=»csharp» source=»../vsto/codesnippet/CSharp/Trin_VstcoreWordAutomationCS/ThisDocument.cs» id=»Snippet72″:::
VB
:::code language=»vb» source=»../vsto/codesnippet/VisualBasic/Trin_VstcoreWordAutomationVB/ThisDocument.vb» id=»Snippet72″:::
The following code example can be used in a VSTO Add-in. This example uses the active document.
C#
:::code language=»csharp» source=»../vsto/codesnippet/CSharp/Trin_VstcoreWordAutomationAddIn/ThisAddIn.cs» id=»Snippet72″:::
VB
:::code language=»vb» source=»../vsto/codesnippet/VisualBasic/Trin_VstcoreWordAutomationAddIn/ThisAddIn.vb» id=»Snippet72″:::
-
Using the xref:Microsoft.Office.Interop.Word.Range.Find%2A property of the xref:Microsoft.Office.Interop.Word.Range object, first clear any existing formatting options, and then search for the string find me.
C#
:::code language=»csharp» source=»../vsto/codesnippet/CSharp/Trin_VstcoreWordAutomationCS/ThisDocument.cs» id=»Snippet73″:::
VB
:::code language=»vb» source=»../vsto/codesnippet/VisualBasic/Trin_VstcoreWordAutomationVB/ThisDocument.vb» id=»Snippet73″:::
-
Display the results of the search in a message box, and select the xref:Microsoft.Office.Interop.Word.Range to make it visible.
C#
:::code language=»csharp» source=»../vsto/codesnippet/CSharp/Trin_VstcoreWordAutomationCS/ThisDocument.cs» id=»Snippet74″:::
VB
:::code language=»vb» source=»../vsto/codesnippet/VisualBasic/Trin_VstcoreWordAutomationVB/ThisDocument.vb» id=»Snippet74″:::
If the search fails, the second paragraph is selected; if it succeeds, the search criteria are displayed.
The following example shows the complete code for a document-level customization. To use this example, run the code from the
ThisDocument
class in your project.C#
:::code language=»csharp» source=»../vsto/codesnippet/CSharp/Trin_VstcoreWordAutomationCS/ThisDocument.cs» id=»Snippet71″:::
VB
:::code language=»vb» source=»../vsto/codesnippet/VisualBasic/Trin_VstcoreWordAutomationVB/ThisDocument.vb» id=»Snippet71″:::
The following example shows the complete code for a VSTO Add-in. To use this example, run the code from the
ThisAddIn
class in your project.C#
:::code language=»csharp» source=»../vsto/codesnippet/CSharp/Trin_VstcoreWordAutomationAddIn/ThisAddIn.cs» id=»Snippet71″:::
VB
:::code language=»vb» source=»../vsto/codesnippet/VisualBasic/Trin_VstcoreWordAutomationAddIn/ThisAddIn.vb» id=»Snippet71″:::
Search for and replace text in documents
The following code searches the current selection and replaces all of the occurrences of the string find me with the string Found.
To search for and replace text in documents
-
Add the following example code to the
ThisDocument
orThisAddIn
class in your project.C#
:::code language=»csharp» source=»../vsto/codesnippet/CSharp/Trin_VstcoreWordAutomationCS/ThisDocument.cs» id=»Snippet75″:::
VB
:::code language=»vb» source=»../vsto/codesnippet/VisualBasic/Trin_VstcoreWordAutomationVB/ThisDocument.vb» id=»Snippet75″:::
The xref:Microsoft.Office.Interop.Word.Find class has a xref:Microsoft.Office.Interop.Word.Find.ClearFormatting%2A method, and the xref:Microsoft.Office.Interop.Word.Replacement class also has its own xref:Microsoft.Office.Interop.Word.Replacement.ClearFormatting%2A method. When you are performing find-and-replace operations, you must use the ClearFormatting method of both objects. If you use it only on the xref:Microsoft.Office.Interop.Word.Find object, you might get unanticipated results in the replacement text.
-
Use the xref:Microsoft.Office.Interop.Word.Find.Execute%2A method of the xref:Microsoft.Office.Interop.Word.Find object to replace each found item. To specify which items to replace, use the Replace parameter. This parameter can be one of the following xref:Microsoft.Office.Interop.Word.WdReplace values:
-
xref:Microsoft.Office.Interop.Word.WdReplace.wdReplaceAll replaces all found items.
-
xref:Microsoft.Office.Interop.Word.WdReplace.wdReplaceNone replaces none of the found items.
-
xref:Microsoft.Office.Interop.Word.WdReplace.wdReplaceOne replaces the first found item.
-
See also
- How to: Programmatically set search options in Word
- How to: Programmatically loop through found items in documents
- How to: Programmatically define and select ranges in documents
- How to: Programmatically restore selections after searches
- Optional parameters in Office solutions
- Remove From My Forums
-
Question
-
I would like to clean up this word document. the below code works. but I would like to better understand Word Interop. instead of finding each line and replace with «» to remove the bottom signature. is there
a way to delete lines starting with «Your Name» and ending with «youremail@server.com» and everything in between? I guess setting a range and delete? and or
deleting everything after a specific find. any help is greatly appreciated.Dim objWord As Word.Application = New Word.Application Dim objDoc As Document = objWord.Documents.Open(LoadDir & tbEMailIfContains.Text & eMailHitCount & ".rtf") objWord.Visible = False 'This does Header!!! Do While objDoc.Content.Find.Execute(FindText:="Subject:", Wrap:=Word.WdFindWrap.wdFindContinue) = True objWord.Selection.Range.Bookmarks("line").Range.Delete() Loop 'This Does Footer objDoc.Content.Find.Execute(FindText:="Your Name", ReplaceWith:="", Replace:=Word.WdReplace.wdReplaceAll) objDoc.Content.Find.Execute(FindText:="Your Title", ReplaceWith:="", Replace:=Word.WdReplace.wdReplaceAll) objDoc.Content.Find.Execute(FindText:="Your Company", ReplaceWith:="", Replace:=Word.WdReplace.wdReplaceAll) objDoc.Content.Find.Execute(FindText:="Your Address", ReplaceWith:="", Replace:=Word.WdReplace.wdReplaceAll) objDoc.Content.Find.Execute(FindText:="Your Work Number", ReplaceWith:="", Replace:=Word.WdReplace.wdReplaceAll) objDoc.Content.Find.Execute(FindText:="Your Cell Number", ReplaceWith:="", Replace:=Word.WdReplace.wdReplaceAll) objDoc.Content.Find.Execute(FindText:="youremail@server.com", ReplaceWith:="", Replace:=Word.WdReplace.wdReplaceAll) objWord.Documents.Close(Word.WdSaveOptions.wdSaveChanges) objWord.Quit()
Work Smarter Not Harder
-
Edited by
Tuesday, June 28, 2016 1:45 PM
-
Edited by
Answers
-
Hi
jimbrown.wsas you asked to find the text and then try to search in document. so I modify the code that I had mentioned above and make little changes in that now it can able to search the text and from that we can get line number and then we will try to delete the range.
Sub Main() Dim objWord As Word.Application = New Word.Application Dim objDoc As Word.Document objDoc = objWord.Documents.Open("C:Usersv-padeeDesktopdem16.docx") objWord.Visible = True Dim rng, myRange, myRange1 As Word.Range Dim start, finish As Integer myRange = objDoc.Content myRange.Find.Execute("Your name:") myRange.Select() start = myRange.Information(Word.WdInformation.wdFirstCharacterLineNumber) myRange1 = objDoc.Content myRange1.Find.Execute("youremail@server.com") myRange1.Select() finish = myRange1.Information(Word.WdInformation.wdFirstCharacterLineNumber) Dim startLocation As Object = objDoc.Sentences(start).Start Dim endLocation As Object = objDoc.Sentences(finish).End ' Supply a Start and End value for the Range. rng = objDoc.Range(Start:=startLocation, End:=endLocation) ' Select the Range rng.Select() rng.Delete() objWord.Documents.Close(Word.WdSaveOptions.wdSaveChanges) objWord.Quit() End Sub
Regards
Deepak
We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
Click
HERE to participate the survey.-
Marked as answer by
jimbrown.net
Thursday, June 30, 2016 7:00 PM
-
Marked as answer by
Задача: вывести данные в документ Word. На самом деле это очень большая и необъятная тема, примерно как сам Word, 90% возможностей которого не используются обычными пользователями. Сузим до более простой и чаще встречающейся на практике задачи, с которой в своей время пришлось столкнуться мне самому: надо вывести красивую справку, договор, отчет или иной документ Word с добавлением данных из кода C#. Само собой должны поддерживаться версии Word до 2007, так что о новых форматах файлов придется забыть.
Для начала вспомним, что в Word есть такая замечательная вещь как шаблоны. Соответственно большую часть сложного оформления можно вынести в них и из кода открывать шаблон и вставлять данные в нужные места. Для начала ограничимся простыми строками (типовая задача в крупных предприятиях — вставка дат, цифр, фио и тому подобных вещей, договор на сумму такую-то, от такой-то даты с фио таким-то с параметрами объекта такими-то).
Задача на текущую статью: открыть из кода C# шаблон Word и что-то в него вставить. Шаблон в формате .dot приготовим заранее, в том же самом ворде. Для связи с ним будем использовать механизм COM Interoperability (сокращенно Interop), то есть запускать отдельный exe-процесс самого Word и через специальный интерфейс управлять им. Интерфейсы слава богу есть и находятся они в специальных библиотеках, поставляемых вместе с Office, но документация по ним крайне невнятная, поведение местами очень странное и не логичное. В версиях Visual Studio 2010 и выше возможности программирования Office расширены, но текущее руководство действительно и для 2008 студии.
Нам надо
1. Подключить нужные библиотеки
2. Открыть шаблон Word
3. Найти в нем нужное место
4. Вставить в него строку с информацией
1. Проект в студии у нас уже должен быть. В разделе Ссылки/References кликаем правой кнопкой, идем в «Добавить ссылку» и ищем Microsoft.Office.Interop.Word. В параметрах добавленной библиотеки ставим true в Копировать локально/Copy local, так как библиотеку надо копировать вместе с исполняемыми файлами проекта.
В код добавляем соответствующие using
using Word = Microsoft.Office.Interop.Word; using System.Reflection;
2. Теперь вам предстоит провести много времени с замечательным интерфейсом Word, который представляет сам текстовый редактор и его потроха в виде разнообразных обьектов. Сейчас важны два — Application и Document. Переменные для них по ряду не очевидных причин лучше объявлять через интерфейсы.
Word._Application application; Word._Document document;
Так же почти все функции Word требуют объектных параметров, даже если внутри них сидят простые строки и логические значения, так что лучше заранее сделать несколько оберток
Object missingObj = System.Reflection.Missing.Value; Object trueObj = true; Object falseObj = false;
Чтобы запустить Word и открыть в нем шаблон с диска (путь известен), потребуется примерно такой код
//создаем обьект приложения word application = new Word.Application(); // создаем путь к файлу Object templatePathObj = "путь к файлу шаблона";; // если вылетим не этом этапе, приложение останется открытым try { document = application.Documents.Add(ref templatePathObj, ref missingObj, ref missingObj, ref missingObj); } catch (Exception error) { document.Close(ref falseObj, ref missingObj, ref missingObj); application.Quit(ref missingObj, ref missingObj, ref missingObj); document = null; application = null; throw error; } _application.Visible = true;
Принципиально важны два момента
1. Мы создаем неуправляемый ресурс, который не соберет сборщик мусора — отдельный процесс в памяти с приложением Word, если мы его не закроем и не выведем на экран, он так и останется там висеть до выключения компьютера. Более того такие ворды могут накапливаться незаметно для пользователя, программист-то еще прибьет их вручную. Заботиться о высвобождения неуправляемого ресурса должен программист.
2. По умолчанию Word запускается невидимым, на экран его выводим мы.
Для начала рассмотрим самый простой и примитивный вариант — поиск и замена строки в документе Word. Некоторые программисты так и работают — ставят в шаблон текстовую метку вроде @@nowDate и заменяют ее на нужное значение.
Пришло время познакомится с фундаментом работы с Word — великим и ужасным объектом Range. Его суть сложно описать словами -это некоторый произвольный кусок документа, диапазон (range), который может включать в себя все что угодно — от пары символов, до таблиц, закладок и прочих интересных вещей. Не стоит путать его с Selection — куском документа, выделенным мышкой, который само собой можно конвертировать в Range. Соотвественно нам надо получить Range для всего документа, найти нужную строку внутри него, получить Range для этой строки и уже внутри этого последнего диапазона заменить текст на требуемый. И не стоит забывать, что документ может иметь сложную структуру с колонтитулами и прочей ересью, возможный универсальный метод для замены всех вхождений данной строки:
// обьектные строки для Word object strToFindObj = strToFind; object replaceStrObj = replaceStr; // диапазон документа Word Word.Range wordRange; //тип поиска и замены object replaceTypeObj; replaceTypeObj = Word.WdReplace.wdReplaceAll; // обходим все разделы документа for (int i = 1; i <= _document.Sections.Count; i++) { // берем всю секцию диапазоном wordRange = _document.Sections[i].Range; /* Обходим редкий глюк в Find, ПРИЗНАННЫЙ MICROSOFT, метод Execute на некоторых машинах вылетает с ошибкой "Заглушке переданы неправильные данные / Stub received bad data" Подробности: http://support.microsoft.com/default.aspx?scid=kb;en-us;313104 // выполняем метод поиска и замены обьекта диапазона ворд wordRange.Find.Execute(ref strToFindObj, ref wordMissing, ref wordMissing, ref wordMissing, ref wordMissing, ref wordMissing, ref wordMissing, ref wordMissing, ref wordMissing, ref replaceStrObj, ref replaceTypeObj, ref wordMissing, ref wordMissing, ref wordMissing, ref wordMissing); */ Word.Find wordFindObj = wordRange.Find; object[] wordFindParameters = new object[15] { strToFindObj, _missingObj, _missingObj, _missingObj, _missingObj, _missingObj, _missingObj, _missingObj, _missingObj, replaceStrObj, replaceTypeObj, _missingObj, _missingObj, _missingObj, _missingObj }; wordFindObj.GetType().InvokeMember("Execute", BindingFlags.InvokeMethod, null, wordFindObj, wordFindParameters); }
Редкий глюк подробно описан здесь.
На самом деле это не самый лучший метод для вставки информации в документ, так как могут возникнуть сложности с уникальными именами для текстовых меток (если текст одной входит в начало другой, данный метод найдет ее и заменит), их совпадением с произвольным текстом и так далее.
Даже если нам надо найти (и например отформатировать) именно строку с текстом внутри документа, лучше всего выдать наружу найденный Range и уже с ним производить разные злодеяния. Получим примерно такой метод:
object stringToFindObj = stringToFind; Word.Range wordRange; bool rangeFound; //в цикле обходим все разделы документа, получаем Range, запускаем поиск // если поиск вернул true, он долже ужать Range до найденное строки, выходим и возвращаем Range // обходим все разделы документа for (int i = 1; i <= _document.Sections.Count; i++) { // берем всю секцию диапазоном wordRange = _document.Sections[i].Range; /* // Обходим редкий глюк в Find, ПРИЗНАННЫЙ MICROSOFT, метод Execute на некоторых машинах вылетает с ошибкой "Заглушке переданы неправильные данные / Stub received bad data" Подробности: http://support.microsoft.com/default.aspx?scid=kb;en-us;313104 // выполняем метод поиска и замены обьекта диапазона ворд rangeFound = wordRange.Find.Execute(ref stringToFindObj, ref wordMissing, ref wordMissing, ref wordMissing, ref wordMissing, ref wordMissing, ref wordMissing, ref wordMissing, ref wordMissing, ref wordMissing, ref wordMissing, ref wordMissing, ref wordMissing, ref wordMissing, ref wordMissing); */ Word.Find wordFindObj = wordRange.Find; object[] wordFindParameters = new object[15] { stringToFindObj, _missingObj, _missingObj, _missingObj, _missingObj, _missingObj, _missingObj, _missingObj, _missingObj, _missingObj, _missingObj, _missingObj, _missingObj, _missingObj, _missingObj }; rangeFound = (bool)wordFindObj.GetType().InvokeMember("Execute", BindingFlags.InvokeMethod, null, wordFindObj, wordFindParameters); if (rangeFound) { return wordRange; } } // если ничего не нашли, возвращаем null return null;
Простейшее решение проблемы уникальности текста (нужно нам найти Range слова Word, но внутри всего документа оно встречается десятки раз) — искать строку внутри строки, сначала найти уникальную строку, потом не уникальную внутри нее, неэстетично, но дешево, надежно и практично.
// оформляем обьектные параметры object stringToFindObj = stringToFind; bool rangeFound; /* Обходим редкий глюк в Find, ПРИЗНАННЫЙ MICROSOFT, метод Execute на некоторых машинах вылетает с ошибкой "Заглушке переданы неправильные данные / Stub received bad data" http://support.microsoft.com/default.aspx?scid=kb;en-us;313104 rangeFound = containerRange.Find.Execute(ref stringToFindObj, ref wordMissing, ref wordMissing, ref wordMissing, ref wordMissing, ref wordMissing, ref wordMissing, ref wordMissing, ref wordMissing, ref wordMissing, ref wordMissing, ref wordMissing, ref wordMissing, ref wordMissing, ref wordMissing); */ Word.Find wordFindObj = containerRange.Find; object[] wordFindParameters = new object[15] { stringToFindObj, _missingObj, _missingObj, _missingObj, _missingObj, _missingObj, _missingObj, _missingObj, _missingObj, _missingObj, _missingObj, _missingObj, _missingObj, _missingObj, _missingObj }; rangeFound = (bool)wordFindObj.GetType().InvokeMember("Execute", BindingFlags.InvokeMethod, null, wordFindObj, wordFindParameters); if (rangeFound) { return containerRange; } else { return null; }
Если строку надо просто заменить, то сойдет простейшее
_range.Text = "Это текст заменит содержимое Range";
Но так как Range является универсальный контейнером для любого куска документа Word, то его возможности неизмеримо шире, часть их будет рассмотрена в дальнейших заметках.
Если нам надо просто встать в начало документа (и что-то вставить уже туда):
object start = 0; object end = 0; _currentRange = _document.Range(ref start, ref end);
Сохранить документ на диск можно следующим образом
Object pathToSaveObj = pathToSaveString; _document.SaveAs(ref pathToSaveObj, Word.WdSaveFormat.wdFormatDocument, ref _missingObj, ref _missingObj, ref _missingObj, ref _missingObj, ref _missingObj, ref _missingObj, ref _missingObj, ref _missingObj, ref _missingObj, ref _missingObj, ref _missingObj, ref _missingObj, ref _missingObj, ref _missingObj);
- Работаем с MS Word из C#, часть 0, класс и тестовый проект-пример WinForms
- Работаем с MS Word из C#, часть 1. Открываем шаблон, ищем текст внутри документа
- Работаем с MS Word из C#, часть 2. Вставляем текст на закладку и форматируем
- Работаем с MS Word из C#, часть 3. Работа с таблицами
- Работаем с MS Word из C#, часть 4. Обьединяем несколько файлов в один, считаем количество страниц
- Microsoft.Office.Interop.Word Namespace
- Range Interface
What I’m trying to do is take Indentifiers that I type into a word doc and set bookmarks on them.
Say I have a Word Doc with the following text
«The Raven» is a narrative poem by the American <Goody> Edgar Allan Poe, first published in January 1845. It is noted for its musicality, <HereIAm> language, and supernatural atmosphere. It tells of a talking raven’s mysterious visit to a distraught lover, <AnotherWord> the man’s slow descent into madness. The lover, often identified as being a student,[1][2] is lamenting the loss of his love, Lenore. The raven, sitting on a bust of Pallas, seems to further instigate his distress with its constant repetition of the word, «Nevermore». Throughout the poem, Poe makes allusions to folklore and various classical works.
I Would like to use something like a Regex to find strings formated like <[SomeText]> and then create a bookmark over <[SomeText]>. IE, in the above paragraph I would create bookmarks fro <AnotherWord>, <Goody>, And <HereIAm>
To do this using Word, I would highlight the <[SomeText]> then goto Insert->Bookmark.
I believe I can figure out how to add the bookmark as long as I get can a Range object that covers the text range of the <[SomeText]> identifier. I’ve tried running a regex on the Word.Content.Text using Text.RegularExpression.Regex and I get find the matches but when I try to create a range from the starting index of the match and the index of the last character its not selecting the right text.
Another problem that I noticed, is if Word.Content.Text is used, it does not return text that is inside a head or footer. I will also need code that can find these identifiers within header and footer fields.
Thanks
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 |
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Data.OleDb; using System.Drawing; using System.Globalization; using System.Linq; using System.Text; using System.Windows.Forms; using Excel = Microsoft.Office.Interop.Excel; using Word = Microsoft.Office.Interop.Word; namespace sourse { class word { Object wordMissing = System.Reflection.Missing.Value; Object wordTrue = true; Object wordFalse = false; public Word.Table tables; //рабочие параметры // если использовать Word.Application и Word.Document получим предупреждение от компиллятора public Word._Application wordApplication; public Word._Document wordDocument; Object templatePathObj; // определяет поведение в случае ошибки при поиске и замене строки, по умолчанию открытый документ и приложенеи Word закрываются public bool CloseIFReplaceFailed = true; /// <summary> /// возвращает количество таблиц в документе /// </summary> /// <returns></returns> public int tableCount() { return wordDocument.Tables.Count; } public bool runMacros(string macros) { try { wordApplication.Run(macros); return true; } catch { MessageBox.Show(@"Ошибка макроса"); return false; } } // фиксированные параметры для передачи приложению Word public void copyToWord(ref word MainDoc, word secondDoc) { Word.Range wordrange = secondDoc.wordApplication.ActiveDocument.Range( secondDoc.wordApplication.ActiveDocument.Content.Start, secondDoc.wordApplication.ActiveDocument.Content.End); wordrange.Copy(); Word.Range w = MainDoc.wordApplication.ActiveDocument.Range( MainDoc.wordApplication.ActiveDocument.Content.End - 1, MainDoc.wordApplication.ActiveDocument.Content.End); w.Paste(); } public void GetFont(Font _font) { Word.Range w = wordApplication.ActiveDocument.Range( wordApplication.ActiveDocument.Content.Start, wordApplication.ActiveDocument.Content.End); w.Font.Name = _font.Name; w.Font.Size = _font.Size; } public bool Visible { get { if (documentClosed()) { throw new Exception("Ошибка при попытке изменить видимость Microsoft Word. Программа или документ уже закрыты."); } return wordApplication.Visible; } set { if (documentClosed()) { throw new Exception("Ошибка при попытке изменить видимость Microsoft Word. Программа или документ уже закрыты."); } wordApplication.Visible = value; } // завершение public bool Visible } // конструктор, создаем по шаблону, потом возможно расширение другими вариантами public word() { wordApplication = new Word.Application(); //создаем ноый документ методом приложения Word по поути к шаблону документа try { wordDocument = wordApplication.Documents.Add(ref wordMissing, ref wordMissing, ref wordMissing, ref wordMissing); } // если произошла ошибка, то приложение Word надо закрыть catch (Exception error) { wordApplication.Quit(ref wordMissing, ref wordMissing, ref wordMissing); wordApplication = null; throw new Exception("Ошибка. Не удалось открыть шаблон документа MS Word. " + error.Message); } // завершение createFromTemplate(string templatePath) } public word(string templatePath) { CreateFromTemplate(templatePath); } // создаем приложение Word и открывает новый документ по заданному файлу шаблона public void CreateFromTemplate(string templatePath) { //создаем обьект приложения word wordApplication = new Word.Application(); // создаем путь к файлу используя имя файла templatePathObj = templatePath; //создаем ноый документ методом приложения Word по поути к шаблону документа try { wordDocument = wordApplication.Documents.Add(ref templatePathObj, ref wordMissing, ref wordMissing, ref wordMissing); } // если произошла ошибка, то приложение Word надо закрыть catch (Exception error) { wordApplication.Quit(ref wordMissing, ref wordMissing, ref wordMissing); wordApplication = null; throw new Exception("Ошибка. Не удалось открыть шаблон документа MS Word. " + error.Message); } // завершение createFromTemplate(string templatePath) } public bool GetTable(int count) { try { var table = wordDocument.Tables[count]; tables = table; return true; } catch { MessageBox.Show(@"Не получилось выявить таблицу"); return false; } } public string Seath(string findStr) { string res = " "; object missing; missing = Type.Missing; object findText = findStr; wordApplication.Selection.Find.ClearFormatting(); if (wordApplication.Selection.Find.Execute(ref findText, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing)) { // MessageBox.Show("Text found."); wordApplication.Selection.Expand(Word.WdUnits.wdLine); res = wordApplication.Selection.Text.Remove(wordApplication.Selection.Text.Length - 1, 1); } return res; } // ПОИСК И ЗАМЕНА ЗАДАННОЙ СТРОКИ public void ReplaceString(string strToFind, string replaceStr, string replaceTypeStr) { if (documentClosed()) { throw new Exception("Ошибка при выполнении поиска и замены в Microsoft Word. Программа или документ уже закрыты."); } // обьектные строки для Word object strToFindObj = strToFind; object replaceStrObj = replaceStr; // диапазон документа Word Word.Range wordRange; //тип поиска и замены object replaceTypeObj; if (replaceTypeStr == "all") { // заменять все найденные вхождения replaceTypeObj = Word.WdReplace.wdReplaceAll; } else if (replaceTypeStr == "one") { // заменять только первое найденное вхождение replaceTypeObj = Word.WdReplace.wdReplaceOne; } else { Close(); throw new Exception("Неизвестный тип поиска и замены в документе Word."); } try { // обходим все разделы документа for (int i = 1; i <= wordDocument.Sections.Count; i++) { // берем всю секцию диапазоном wordRange = wordDocument.Sections[i].Range; // выполняем метод поискаи замены обьекта диапазона ворд wordRange.Find.Execute(ref strToFindObj, ref wordMissing, ref wordMissing, ref wordMissing, ref wordMissing, ref wordMissing, ref wordMissing, ref wordMissing, ref wordMissing, ref replaceStrObj, ref replaceTypeObj, ref wordMissing, ref wordMissing, ref wordMissing, ref wordMissing); } } catch (Exception error) { if (CloseIFReplaceFailed) { this.Close(); } throw new Exception("Ошибка при выполнении поиска и замены в документе Word. " + error.Message); } // завершение функции поиска и замены SearchAndReplace } // тоже поиск и замена private void WordReplace(string old_str, string new_str) { foreach (Microsoft.Office.Interop.Word.Range tmpRange in wordDocument.StoryRanges) { // Set the text to find and replace tmpRange.Find.Text = old_str; tmpRange.Find.Replacement.Text = new_str; // Set the Find.Wrap property to continue (so it doesn't // prompt the user or stop when it hits the end of // the section) tmpRange.Find.Wrap = Microsoft.Office.Interop.Word.WdFindWrap.wdFindContinue; // Declare an object to pass as a parameter that sets // the Replace parameter to the "wdReplaceAll" enum object replaceAll = Microsoft.Office.Interop.Word.WdReplace.wdReplaceAll; object missing = System.Type.Missing; // Execute the Find and Replace -- notice that the // 11th parameter is the "replaceAll" enum object tmpRange.Find.Execute(ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref replaceAll, ref missing, ref missing, ref missing, ref missing); } } // закрытие открытого документа и приложения public void Close() { if (documentClosed()) { throw new Exception("Ошибка при попытке закрыть Microsoft Word. Программа или документ уже закрыты."); } wordDocument.Close(ref wordFalse, ref wordMissing, ref wordMissing); wordApplication.Quit(ref wordMissing, ref wordMissing, ref wordMissing); wordDocument = null; wordApplication = null; } // если документ уже закрыт, true private bool documentClosed() { if (this.wordApplication == null || this.wordDocument == null) { return true; } else { return false; } } // завершение class WordDocument } } |
Вопрос был бы простым, но добавленное к нему дополнительное предложение оказалось для меня большой головной болью. Подвох в том, что мне нужны не все выделенные слова, а фразы из файла Word. Я написал следующий код:
using Word = Microsoft.Office.Interop.Word;
private void button1_Click(object sender, EventArgs e)
{
try
{
Word.ApplicationClass wordObject = new Word.ApplicationClass();
wordObject.Visible = false;
object file = "D:\mywordfile.docx";
object nullobject = System.Reflection.Missing.Value;
Word.Document thisDoc = wordObject.Documents.Open(ref file, ref nullobject, ref nullobject, ref nullobject, ref nullobject, ref nullobject, ref nullobject, ref nullobject, ref nullobject, ref nullobject, ref nullobject, ref nullobject, ref nullobject, ref nullobject, ref nullobject, ref nullobject);
List<string> wordHighlights = new List<string>();
//Let myRange be some Range which has my text under consideration
int prevStart = 0;
int prevEnd = 0;
int thisStart = 0;
int thisEnd = 0;
string tempStr = "";
foreach (Word.Range cellWordRange in myRange.Words)
{
if (cellWordRange.HighlightColorIndex.ToString() == "wdNoHighlight")
{
continue;
}
else
{
thisStart = cellWordRange.Start;
thisEnd = cellWordRange.End;
string cellWordText = cellWordRange.Text.Trim();
if (cellWordText.Length >= 1) // valid word length, non-whitespace
{
if (thisStart == prevEnd) // If this word is contiguously highlighted with previous highlighted word
{
tempStr = String.Concat(tempStr, " "+cellWordText); // Concatenate with previous contiguously highlighted word
}
else
{
if (tempStr.Length > 0) // If some string has been concatenated in previous iterations
{
wordHighlights.Add(tempStr);
}
tempStr = "";
tempStr = cellWordText;
}
}
prevStart = thisStart;
prevEnd = thisEnd;
}
}
foreach (string highlightedString in wordHighlights)
{
MessageBox.Show(highlightedString);
}
}
catch (Exception j)
{
MessageBox.Show(j.Message);
}
}
Теперь рассмотрим следующий текст:
Верит о борьбе с холестерином, сгоранием, профилактикой и лечением, и фокусником.
Теперь предположим, что кто-то выделил «du cholestérol«, мой код явно выбирает два слова «du» и «cholestérol«. Как сделать так, чтобы постоянно выделенная область отображалась как одно слово? Я имею в виду «du cholestérol» должен быть возвращен как один объект в List
, Любая логика, что мы сканируем символ char по символу, отмечаем начальную точку выделения как начальную точку выделения, а конечную точку выделения как конечную точку выделения?
PS: Если есть библиотека с необходимыми возможностями на любом другом языке, пожалуйста, дайте мне знать, поскольку сценарий не зависит от языка. Мне нужно только получить желаемые результаты как-то.
РЕДАКТИРОВАТЬ: изменил код с Start
а также End
как предположил Оливер Ханаппи. Но проблема по-прежнему заключается в том, что если есть две такие выделенные фразы, разделенные только пробелом, программа считает обе фразы одной. Просто потому, что он читает Words
а не пробелы. Может потребоваться некоторые правки if (thisStart == prevEnd)
?
2013-03-20 12:56
4
ответа
Решение
Вы можете сделать это гораздо эффективнее с помощью Find, который будет искать быстрее и выделять весь соответствующий текст. См. Ссылку здесь http://msdn.microsoft.com/en-us/library/office/bb258967%28v=office.12%29.aspx
Вот пример в VBA, который печатает все вхождения выделенного текста:
Sub TestFind()
Dim myRange As Range
Set myRange = ActiveDocument.Content ' search entire document
With myRange.Find
.Highlight = True
Do While .Execute = True ' loop while highlighted text is found
Debug.Print myRange.Text ' myRange is changed to contain the found text
Loop
End With
End Sub
Надеюсь, это поможет вам лучше понять.
2013-03-20 14:12
Вы можете посмотреть свойства Start и End диапазонов и проверить, равен ли конец первого диапазона началу второго.
В качестве альтернативы вы можете переместить диапазон на одно слово (см. WdUnits.wdWord), а затем проверить, соответствуют ли перемещенные начало и конец началу и концу второго слова.
2013-03-20 13:29
grahamj42 ответ в порядке, я перевел его на C#. Если вы хотите найти совпадения во всем документе, используйте:
Word.Range content = thisDoc.Content
Но помните, что это только mainStoryRange, если вы хотите сопоставить слова, например, сноски, которые вы должны использовать:
Word.StoryRanges stories = null;
stories = thisDoc.StoryRanges;
Word.Range footnoteRange = stories[Word.WdStoryType.wdFootnotesStory]
Мой код:
Word.Find find = null;
Word.Range duplicate = null;
try
{
duplicate = range.Duplicate;
find = duplicate.Find;
find.Highlight = 1;
object str = "";
object missing = System.Type.Missing;
object objTrue = true;
object replace = Word.WdReplace.wdReplaceNone;
bool result = find.Execute(ref str, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref objTrue, ref str, ref replace, ref missing, ref missing, ref missing, ref missing);
while (result)
{
// code to store range text
// use duplicate.Text property
result = find.Execute(ref str, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref objTrue, ref str, ref replace, ref missing, ref missing, ref missing, ref missing);
}
}
finally
{
if (find != null) Marshal.ReleaseComObject(find);
if (duplicate != null) Marshal.ReleaseComObject(duplicate);
}
2013-04-04 14:06
Я начал с логики Оливера, все было хорошо, но тестирование показало, что этот метод не учитывает пробелы. Таким образом, выделенные фразы, разделенные пробелом, не разделяются. Я использовал подход кода VB, предоставленный grahamj42, и добавил его в качестве библиотеки классов и включил ссылку в мой проект форм окон C#.
Мой C# Windows проект формы:
using Word = Microsoft.Office.Interop.Word;
а потом я изменил try
блок как:
Word.ApplicationClass wordObject = new Word.ApplicationClass();
wordObject.Visible = false;
object file = "D:\mywordfile.docx";
object nullobject = System.Reflection.Missing.Value;
Word.Document thisDoc = wordObject.Documents.Open(ref file, ref nullobject, ref nullobject, ref nullobject, ref nullobject, ref nullobject, ref nullobject, ref nullobject, ref nullobject, ref nullobject, ref nullobject, ref nullobject, ref nullobject, ref nullobject, ref nullobject, ref nullobject);
List<string> wordHighlights = new List<string>();
// Let myRange be some Range, which has been already selected programatically here
WordMacroClasses.Highlighting macroObj = new WordMacroClasses.Highlighting();
List<string> hiWords = macroObj.HighlightRange(myRange, myRange.End);
foreach (string hitext in hiWords)
{
wordHighlights.Add(hitext);
}
А вот и Range.Find
код в библиотеке классов VB, который просто принимает Range
И его Range.Last
и возвращает List(Of String)
:
Public Class Highlighting
Public Function HighlightRange(ByVal myRange As Microsoft.Office.Interop.Word.Range, ByVal rangeLimit As Integer) As List(Of String)
Dim Highlights As New List(Of String)
Dim i As Integer
i = 0
With myRange.Find
.Highlight = True
Do While .Execute = True ' loop while highlighted text is found
If (myRange.Start < rangeLimit) Then Highlights.Add(myRange.Text)
Loop
End With
Return Highlights
End Function
End Class
2013-03-22 10:44
public ResultType_enum Create(Document document, Word.Application application, out Word._Document doc, out string message) { try { isWork = true; message = ""; Object trueObj = true; Object falseObj = false; Object begin = Type.Missing; Object end = Type.Missing; doc = null; // если вылетим не этом этапе, приложение останется открытым try { doc = application.Documents.Add(ref missingObj, ref missingObj, ref missingObj, ref missingObj); // Общий Стиль object patternstyle = Word.WdStyleType.wdStyleTypeParagraph; Word.Style wordstyle = doc.Styles.Add("myStyle", ref patternstyle); wordstyle.Font.Size = 9; wordstyle.Font.Name = "Times New Roman"; Word.Range wordrange = doc.Range(ref begin, ref end); object oWordStyle = wordstyle; wordrange.set_Style(ref oWordStyle); // Вставляем параграфы doc.Paragraphs.Add(ref missingObj); doc.Paragraphs.Add(ref missingObj); doc.Paragraphs.Add(ref missingObj); doc.Paragraphs.Add(ref missingObj); doc.Paragraphs.Add(ref missingObj); doc.Paragraphs.Add(ref missingObj); doc.Paragraphs.Add(ref missingObj); doc.Paragraphs.Add(ref missingObj); doc.Paragraphs.Add(ref missingObj); doc.Paragraphs.Add(ref missingObj); doc.Paragraphs[1].Range.Text = "«Утверждаю»"; doc.Paragraphs[1].Alignment = Word.WdParagraphAlignment.wdAlignParagraphLeft; doc.Paragraphs[1].Range.ParagraphFormat.LeftIndent = 300; doc.Paragraphs[1].Range.ParagraphFormat.LineSpacing = 11; doc.Paragraphs[1].SpaceAfter = 0; doc.Paragraphs[1].SpaceBefore = 0; doc.Paragraphs[2].LineUnitAfter = 0; doc.Paragraphs[2].LineUnitBefore = 0; doc.Paragraphs[3].LineUnitAfter = 0; doc.Paragraphs[3].LineUnitBefore = 0; doc.Paragraphs[4].LineUnitAfter = 0; doc.Paragraphs[4].LineUnitBefore = 0; doc.Paragraphs[2].Range.Text = "Руководитель"; doc.Paragraphs[2].Alignment = Word.WdParagraphAlignment.wdAlignParagraphLeft; doc.Paragraphs[2].Range.ParagraphFormat.LeftIndent = 300; doc.Paragraphs[4].Range.Text = "Форма 2. Сведения о качестве, технических характеристиках товара, его безопасности, функциональных характеристиках (потребительских свойствах) товара, размере и иные сведения о товаре, представление которых предусмотрено документацией об аукционе в электронной форме"; doc.Paragraphs[4].Alignment = Word.WdParagraphAlignment.wdAlignParagraphCenter; // Подсчитываем количество строк у продуктов (потому что одно свойство продукта занимает одну строку) int propertiesCount = 0; foreach (Product product in document.Products) { var myTemplate = product.Templates.FirstOrDefault(m => m.Name.Trim().ToLower() == "форма 2"); IEnumerable<Property> productProperties = product.Properties.SelectMany(m => m.ParamValues.Where(p => myTemplate.Param.Contains(p.Param))).Select(f => f.Property).Distinct(); propertiesCount += productProperties.Count(); } Object defaultTableBehavior = Word.WdDefaultTableBehavior.wdWord9TableBehavior; Object autoFitBehavior = Word.WdAutoFitBehavior.wdAutoFitWindow; Word.Table wordtable = doc.Tables.Add(doc.Paragraphs[5].Range, 3 + propertiesCount, 8, ref defaultTableBehavior, ref autoFitBehavior); // Объединение ячеек object begCell = wordtable.Cell(1, 1).Range.Start; object endCell = wordtable.Cell(2, 1).Range.End; Word.Range wordcellrange = doc.Range(ref begCell, ref endCell); wordcellrange.Select(); application.Selection.Cells.Merge(); begCell = wordtable.Cell(1, 2).Range.Start; endCell = wordtable.Cell(2, 2).Range.End; wordcellrange = doc.Range(ref begCell, ref endCell); wordcellrange.Select(); application.Selection.Cells.Merge(); begCell = wordtable.Cell(1, 3).Range.Start; endCell = wordtable.Cell(2, 3).Range.End; wordcellrange = doc.Range(ref begCell, ref endCell); wordcellrange.Select(); application.Selection.Cells.Merge(); begCell = wordtable.Cell(1, 4).Range.Start; endCell = wordtable.Cell(1, 6).Range.End; wordcellrange = doc.Range(ref begCell, ref endCell); wordcellrange.Select(); application.Selection.Cells.Merge(); begCell = wordtable.Cell(1, 5).Range.Start; endCell = wordtable.Cell(2, 7).Range.End; wordcellrange = doc.Range(ref begCell, ref endCell); wordcellrange.Select(); application.Selection.Cells.Merge(); begCell = wordtable.Cell(1, 6).Range.Start; endCell = wordtable.Cell(2, 8).Range.End; wordcellrange = doc.Range(ref begCell, ref endCell); wordcellrange.Select(); application.Selection.Cells.Merge(); /*begCell = wordtable.Cell(4, 6).Range.Start; endCell = wordtable.Cell(propertiesCount + 4, 6).Range.End; wordcellrange = doc.Range(ref begCell, ref endCell); wordcellrange.Select(); application.Selection.Cells.Merge();*/ // Окраска строки с номерами begCell = wordtable.Cell(3, 1).Range.Start; endCell = wordtable.Cell(3, 8).Range.End; wordcellrange = doc.Range(ref begCell, ref endCell); wordcellrange.Select(); application.Selection.Shading.BackgroundPatternColor = Word.WdColor.wdColorGray10; // Заполнение заголовка doc.Tables[1].Cell(1, 1).Range.Text = "№ п/п"; doc.Tables[1].Cell(1, 1).Range.Paragraphs.Alignment = Word.WdParagraphAlignment.wdAlignParagraphCenter; doc.Tables[1].Cell(1, 2).Range.Text = "Наименование материала"; doc.Tables[1].Cell(1, 2).Range.Paragraphs.Alignment = Word.WdParagraphAlignment.wdAlignParagraphCenter; doc.Tables[1].Cell(1, 3).Range.Text = "Указание на товарный знак (его словесное обозначение) (при наличии), знак обслуживания (при наличии), фирменное наименование (при наличии), патенты (при наличии), полезные модели (при наличии), промышленные образцы (при наличии), наименование страны происхождения товара"; doc.Tables[1].Cell(1, 3).Range.Paragraphs.Alignment = Word.WdParagraphAlignment.wdAlignParagraphCenter; doc.Tables[1].Cell(1, 4).Range.Text = "Технические характеристики"; doc.Tables[1].Cell(1, 4).Range.Paragraphs.Alignment = Word.WdParagraphAlignment.wdAlignParagraphCenter; doc.Tables[1].Cell(2, 4).Range.Text = "Требуемый параметр"; doc.Tables[1].Cell(2, 4).Range.Paragraphs.Alignment = Word.WdParagraphAlignment.wdAlignParagraphCenter; doc.Tables[1].Cell(2, 5).Range.Text = "Требуемое значение"; doc.Tables[1].Cell(2, 5).Range.Paragraphs.Alignment = Word.WdParagraphAlignment.wdAlignParagraphCenter; doc.Tables[1].Cell(2, 6).Range.Text = "Значение, предлагаемое участником"; doc.Tables[1].Cell(2, 6).Range.Paragraphs.Alignment = Word.WdParagraphAlignment.wdAlignParagraphCenter; doc.Tables[1].Cell(1, 5).Range.Text = "Единица измерения"; doc.Tables[1].Cell(1, 5).Range.Paragraphs.Alignment = Word.WdParagraphAlignment.wdAlignParagraphCenter; doc.Tables[1].Cell(1, 6).Range.Text = "Сведения о сертификации"; doc.Tables[1].Cell(1, 6).Range.Paragraphs.Alignment = Word.WdParagraphAlignment.wdAlignParagraphCenter; doc.Tables[1].Cell(3, 1).Range.Text = "1"; doc.Tables[1].Cell(3, 1).Range.Paragraphs.Alignment = Word.WdParagraphAlignment.wdAlignParagraphCenter; doc.Tables[1].Cell(3, 2).Range.Text = "2"; doc.Tables[1].Cell(3, 2).Range.Paragraphs.Alignment = Word.WdParagraphAlignment.wdAlignParagraphCenter; doc.Tables[1].Cell(3, 3).Range.Text = "3"; doc.Tables[1].Cell(3, 3).Range.Paragraphs.Alignment = Word.WdParagraphAlignment.wdAlignParagraphCenter; doc.Tables[1].Cell(3, 4).Range.Text = "4"; doc.Tables[1].Cell(3, 4).Range.Paragraphs.Alignment = Word.WdParagraphAlignment.wdAlignParagraphCenter; doc.Tables[1].Cell(3, 5).Range.Text = "5"; doc.Tables[1].Cell(3, 5).Range.Paragraphs.Alignment = Word.WdParagraphAlignment.wdAlignParagraphCenter; doc.Tables[1].Cell(3, 6).Range.Text = "6"; doc.Tables[1].Cell(3, 6).Range.Paragraphs.Alignment = Word.WdParagraphAlignment.wdAlignParagraphCenter; doc.Tables[1].Cell(3, 7).Range.Text = "7"; doc.Tables[1].Cell(3, 7).Range.Paragraphs.Alignment = Word.WdParagraphAlignment.wdAlignParagraphCenter; doc.Tables[1].Cell(3, 8).Range.Text = "8"; doc.Tables[1].Cell(3, 8).Range.Paragraphs.Alignment = Word.WdParagraphAlignment.wdAlignParagraphCenter; // Заполняем продукты ParamValue paramValue = null; int productIndexCompilator = 0; int propertyIndexCompilator = 0; for (int i = 0; i < propertiesCount; i++) { if (!isWork) break; // Получаем свойства продукта на шаблон var myTemplate = document.Products.ElementAt(productIndexCompilator).Templates.FirstOrDefault(m => m.Name.Trim().ToLower() == "форма 2"); IEnumerable<Property> productProperties = document.Products.ElementAt(productIndexCompilator).Properties.SelectMany(m => m.ParamValues.Where(p => myTemplate.Param.Contains(p.Param))).Select(f => f.Property).Distinct(); if (propertyIndexCompilator == 0) { // Объединяем ячейки по продукту (т.к. свойство занимает строку) begCell = wordtable.Cell(i + 4, 1).Range.Start; endCell = wordtable.Cell(i + 4 + productProperties.Count() - 1, 1).Range.End; wordcellrange = doc.Range(ref begCell, ref endCell); wordcellrange.Select(); try { application.Selection.Cells.Merge(); } catch { } begCell = wordtable.Cell(i + 4, 2).Range.Start; endCell = wordtable.Cell(i + 4 + productProperties.Count() - 1, 2).Range.End; wordcellrange = doc.Range(ref begCell, ref endCell); wordcellrange.Select(); try { application.Selection.Cells.Merge(); } catch { } begCell = wordtable.Cell(i + 4, 3).Range.Start; endCell = wordtable.Cell(i + 4 + productProperties.Count() - 1, 3).Range.End; wordcellrange = doc.Range(ref begCell, ref endCell); wordcellrange.Select(); try { application.Selection.Cells.Merge(); } catch { } begCell = wordtable.Cell(i + 4, 8).Range.Start; endCell = wordtable.Cell(i + 4 + productProperties.Count() - 1, 8).Range.End; wordcellrange = doc.Range(ref begCell, ref endCell); wordcellrange.Select(); try { application.Selection.Cells.Merge(); } catch { } doc.Tables[1].Cell(i + 4, 1).Range.Text = Convert.ToString(productIndexCompilator + 1) + '.'; doc.Tables[1].Cell(i + 4, 1).Range.Paragraphs.Alignment = Word.WdParagraphAlignment.wdAlignParagraphCenter; doc.Tables[1].Cell(i + 4, 2).Range.Text = document.Products.ElementAt(productIndexCompilator).Name; doc.Tables[1].Cell(i + 4, 2).Range.Paragraphs.Alignment = Word.WdParagraphAlignment.wdAlignParagraphJustify; doc.Tables[1].Cell(i + 4, 3).Range.Text = document.Products.ElementAt(productIndexCompilator).TradeMark; doc.Tables[1].Cell(i + 4, 3).Range.Paragraphs.Alignment = Word.WdParagraphAlignment.wdAlignParagraphJustify; // Сертификация paramValue = productProperties.ElementAt(propertyIndexCompilator).ParamValues.FirstOrDefault(m => m.Param.Name == "Сертификация"); if (paramValue != null) { doc.Tables[1].Cell(i + 4, 8).Range.Text = paramValue.Value; } else { doc.Tables[1].Cell(i + 4, 8).Range.Text = ""; } doc.Tables[1].Cell(i + 4, 8).Range.Paragraphs.Alignment = Word.WdParagraphAlignment.wdAlignParagraphCenter; } // Требуемый параметр paramValue = productProperties.ElementAt(propertyIndexCompilator).ParamValues.FirstOrDefault(m => m.Param.Name == "Требуемый параметр"); if (paramValue != null) { doc.Tables[1].Cell(i + 4, 4).Range.Text = paramValue.Value; } else { doc.Tables[1].Cell(i + 4, 4).Range.Text = ""; } doc.Tables[1].Cell(i + 4, 4).Range.Paragraphs.Alignment = Word.WdParagraphAlignment.wdAlignParagraphCenter; // Требуемое значение paramValue = productProperties.ElementAt(propertyIndexCompilator).ParamValues.FirstOrDefault(m => m.Param.Name == "Требуемое значение"); if (paramValue != null) { doc.Tables[1].Cell(i + 4, 5).Range.Text = paramValue.Value; } else { doc.Tables[1].Cell(i + 4, 5).Range.Text = ""; } doc.Tables[1].Cell(i + 4, 5).Range.Paragraphs.Alignment = Word.WdParagraphAlignment.wdAlignParagraphCenter; // Значение, предлагаемое участником paramValue = productProperties.ElementAt(propertyIndexCompilator).ParamValues.FirstOrDefault(m => m.Param.Name == "Значение, предлагаемое участником"); if (paramValue != null) { doc.Tables[1].Cell(i + 4, 6).Range.Text = paramValue.Value; } else { doc.Tables[1].Cell(i + 4, 6).Range.Text = ""; } doc.Tables[1].Cell(i + 4, 6).Range.Paragraphs.Alignment = Word.WdParagraphAlignment.wdAlignParagraphCenter; // Единица измерения paramValue = productProperties.ElementAt(propertyIndexCompilator).ParamValues.FirstOrDefault(m => m.Param.Name == "Единица измерения"); if (paramValue != null) { doc.Tables[1].Cell(i + 4, 7).Range.Text = paramValue.Value; } else { doc.Tables[1].Cell(i + 4, 7).Range.Text = ""; } doc.Tables[1].Cell(i + 4, 7).Range.Paragraphs.Alignment = Word.WdParagraphAlignment.wdAlignParagraphCenter; propertyIndexCompilator++; if (productProperties.Count() == propertyIndexCompilator) { propertyIndexCompilator = 0; productIndexCompilator++; } } } catch (Exception er) { if (doc != null) doc.Close(ref falseObj, ref missingObj, ref missingObj); doc = null; } application.Visible = true; return ResultType_enum.Done; } catch (Exception ex) { doc = null; message = ex.Message + 'n' + ex.StackTrace; return ResultType_enum.Error; } finally { isWork = false; } }