Как найти выделенный текст из файла Word в C# с помощью Microsoft.Office.Interop.Word?
Вопрос был бы простым, но добавленное к нему дополнительное предложение оказалось для меня большой головной болью. Подвох в том, что мне нужны не все выделенные слова, а фразы из файла 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)
?
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
Надеюсь, это поможет вам лучше понять.
Вы можете посмотреть свойства Start и End диапазонов и проверить, равен ли конец первого диапазона началу второго.
В качестве альтернативы вы можете переместить диапазон на одно слово (см. WdUnits.wdWord), а затем проверить, соответствуют ли перемещенные начало и конец началу и концу второго слова.
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);
}
Я начал с логики Оливера, все было хорошо, но тестирование показало, что этот метод не учитывает пробелы. Таким образом, выделенные фразы, разделенные пробелом, не разделяются. Я использовал подход кода 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