Как найти выделенный текст из файла 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
Другие вопросы по тегам