Laden...

Rechtschreibprüfung mit Word

Erstellt von Rainbird vor 16 Jahren Letzter Beitrag vor 13 Jahren 11.599 Views
Rainbird Themenstarter:in
3.728 Beiträge seit 2005
vor 16 Jahren
Rechtschreibprüfung mit Word

Beschreibung:

Dieses Snippet macht die Rechtschreibprüfung von Microsoft Word für eigene Anwendungen direkt nutzbar.

Microsoft Word 2000 oder höher muss installiert sein.

Die Anwendung ist denkbar einfach:

  1. Variable für Word-Instanz anlegen

object wordApp;

  1. Microsoft Word im Hintergund starten

wordApp=SpellChecker.StartWinword();

  1. Text auf Rechtschreibfehler prüfen

IList<string> wrongWords=SpellChecker.CheckSpelling("Hallo Welt!",wordApp);

  1. Microsoft Word schließen

SpellChecker.QuitWinword(wordApp);

Die Funktion CheckSpelling gibt eine String-Liste zurück, die alle falsch geschriebenen Wörter des Textes enthält.

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Reflection;

/// <summary>
/// Rechtschreibprüfung mit Word.
/// </summary>
public class SpellChecker
{
    /// <summary>
    /// Startet Microsoft Word im Hintergrund und gibt ein Word.Application-Objekt davon zurück.
    /// </summary>
    public static object StartWinword()
    {
        // Typen-Information für Word abfragen 
        Type wordType = Type.GetTypeFromProgID("Word.Application");

        // Wenn Word installiert ist ...
        if (wordType != null)
        {
            // Word-Instanz erzeugen
            object wordApp=Activator.CreateInstance(wordType);

            // Dokumenten-Auflistung adressieren
            object documents = wordType.InvokeMember("Documents", BindingFlags.GetProperty | BindingFlags.OptionalParamBinding, null, wordApp, new object[0]);

            // Leeres Dokument einfügen
            documents.GetType().InvokeMember("Add", BindingFlags.InvokeMethod | BindingFlags.OptionalParamBinding, null, documents, new object[0]);

            // Word-Instanz zurückgeben
            return wordApp;
        }
        else
            // Ausnahme werfen
            throw new ApplicationException("Microsoft Word ist nicht installiert! Die Rechtschreibprüfung benötigt Microsoft Word.");
    }

        /// <summary>
        /// Beendet eine bestimmte Instanz von microsoft Word.
        /// </summary>
        /// <param name="wordApp">Word.Application-Objekt</param>
        public static void QuitWinword(object wordApp)
        {
        // Typen-Information des Word.Application-Objekt ermitteln
        Type wordType = wordApp.GetType();

        // Dokumenten-Auflistung adressieren
        object documents = wordType.InvokeMember("Documents", BindingFlags.GetProperty | BindingFlags.OptionalParamBinding, null, wordApp, new object[0]);
        
        // Leeres Dokument einfügen
        documents.GetType().InvokeMember("Add", BindingFlags.InvokeMethod | BindingFlags.OptionalParamBinding, null, documents, new object[0]);

        // Word schließen
        wordType.InvokeMember("Quit", BindingFlags.InvokeMethod | BindingFlags.OptionalParamBinding, null, wordApp, new object[1] { 0 });

        // Word-Instanz entsorgen
        Marshal.FinalReleaseComObject(wordApp);
    }

    /// <summary>
    /// Führt eine Rechtschreibprüfung für einen bestimmten Text durch.
    /// </summary>
    /// <param name="wordApp">Word.Application-Objekt</param>
    /// <param name="text">Text</param>
    /// <returns>Liste der Wörter, die falsch geschrieben sind</returns>
    public static IList<string> CheckSpelling(object wordApp, string text)
    { 
        // Typen-Information des Word.Application-Objekt ermitteln
        Type wordType = wordApp.GetType();

        // Liste für falsche Wörter erzeugen
        IList<string> wrongWords=new List<string>();

        // Sonderzeichen aus Text entfernen
        text = text.Replace(''.'', '' '');
        text = text.Replace('','', '' '');
        text = text.Replace('':'', '' '');
        text = text.Replace('';'', '' '');
        text = text.Replace(''"'', '' '');
        text = text.Replace(''('', '' '');
        text = text.Replace('')'', '' '');
        text = text.Replace(''['', '' '');
        text = text.Replace('']'', '' '');

        // Text in Wörter zerlegen
        string[] words = text.Split('' '');
                    
        // Alle Wörter durchlaufen
        foreach (string word in words)
        {
            // Rechtschreibung des Wortes prüfen 
            bool spellCheckResult = (bool)wordType.InvokeMember("CheckSpelling", BindingFlags.InvokeMethod | BindingFlags.OptionalParamBinding, null, wordApp, new object[1] { word });

            // Wenn das Wort nicht richtig geschrieben ist ...
            if (!spellCheckResult)
            {
                // Wort zur Liste zufügen
                wrongWords.Add(word.Trim());
            }
        }
        // Liste zurückgeben
        return wrongWords;            
    }
}

Schlagwörter: Rechtschreibprüfung,spell check,spelling,Word,Winword,Office

Quelle: .NET-Snippets

M
9 Beiträge seit 2009
vor 15 Jahren
Laufzeit

Hallo zusammen,

ich muss in meiner Anwendung auch eine Rechtschreibprüfung machen und hab deshalb oben stehenden Code in meine Anwendung kopiert. Funktioniert auch wirklich super, allerdings habe ich zum Teil Texte, in denen 5000 Wörter und mehr geprüft werden müssen und das dauert dann bei mir 5Min und länger.
Kann das sein oder muss da bei mir noch ein Fehler liegen und gibt es eine Möglichkeit, dass das schneller geht?
Danke für die Antworten

Liebe Grüße
meli

Gelöschter Account
vor 15 Jahren

in dem fall musst du diese schleife optimieren:

string[] words = text.Split('' '');
                    
        // Alle Wörter durchlaufen

        foreach (string word in words)
        {

besser wäre eine whileschleife, wo du durch die character des textes iterierst und nur bei jedem leerzeichen reagierst.

M
9 Beiträge seit 2009
vor 15 Jahren

Hallo,

um ehrlich zu sein, verstehe ich nicht, wie durch deinen Lösungsvorschlag die Performanz steigen soll.
Die Rechtschreibprüfung muss ja wortweise laufen und nicht characterweise. Vor allen Dingen läuft eine Schleife über die Zeichen eines Textes ja auch xmal öfter als über die Wörter eines Textes.
Das Performanceproblem liegt auch nicht bei der Zeile
string[] words = text.Split('' ''); das geht selbst im debugmodus serh schnell. problem ist, dass die Methode

 bool spellCheckResult = (bool)wordType.InvokeMember("CheckSpelling", BindingFlags.InvokeMethod | BindingFlags.OptionalParamBinding, null, wordApp, new object[1] { word });

für jedes Wort erneut aufgerufen wird. Ich hatte die Hoffnung, dass man vielleicht den gesamten Text übergeben kann und mit der Word -rechtschreibprüfung abgeglichen wird und nicht jedes Wort einzeln.

Gelöschter Account
vor 15 Jahren

Die Rechtschreibprüfung muss ja wortweise laufen und nicht characterweise.

-->

und nur bei jedem leerzeichen reagierst.

Vor allen Dingen läuft eine Schleife über die Zeichen eines Textes ja auch xmal öfter als über die Wörter eines Textes.

eine schleife über die zeichen eines textes läuft exakt 1 mal durch wohingegen eine schleife um alle wörter zu bekommen um in einer schleife diese zu iterieren 2 mal läuft.

49.485 Beiträge seit 2005
vor 15 Jahren

Hallo meli143,

so wie ich das sehe, liefert die Rechtschreibprüfung nur ein bool als Ergebnis. Daher sehe ich nicht, wie es funktionierten soll, wenn man mehrere Worte auf einmal übergibt.

Du kannst aber die Performance deutlich steigern, wenn du jedes Wort (egal wieoft es vorkommt) nur einmal prüfst und dabei Worte, die in der deutschen Sprache häufig vorkommen, nicht von Word prüfen lässt, sondern mit einer eigenen Liste selber prüfst.

Beides kann man leicht über HashSets<String> (bzw. unter .NET 2.0 Dictionary<String,bool>) realisieren. Siehe dazu [Artikel] Grundlegendes zu Hashtable/Dictionary.

Eine weitere Diskussion meines Vorschlag sprengt aber hier in ".NET-Komponenten und C#-Snippets" den Rahmen, weshalb sie bitte unterbleiben sollte. Vielen Dank!

Dass das Split nicht das Problem ist, sehe ich wie du. Das geht fix.

herbivore

2.760 Beiträge seit 2006
vor 13 Jahren

Hallo Rainbird,

danke für die Anregung. Kann man immer mal ganz gut gebrauchen. Habe das ganze ein wenig abgewandelt so dass es den aus z.B. Outlook bekannten Dialog verwendet.

Verwendung ist einfach:
String rein, string raus.

Hier der Code:


      private string CheckSpellingDialog(string text) {
         if (string.IsNullOrEmpty(text))
            return "";

         Type wordType = Type.GetTypeFromProgID("Word.Application");
         Type documentType;

         object wordApp = null;
         object documents = null;
         object document = null;
         
         object optional = Missing.Value;
         object visible = false;

         if (wordType != null) {
            wordApp = Activator.CreateInstance(wordType);
            documents = wordType.InvokeMember("Documents", BindingFlags.GetProperty | BindingFlags.OptionalParamBinding, null, wordApp, new object[0]);
            document = documents.GetType().InvokeMember("Add", BindingFlags.InvokeMethod | BindingFlags.OptionalParamBinding, null, documents, new object[4] {
               optional,
               optional,
               optional,
               visible
            });
            documentType = document.GetType();

         } else {
            throw new ApplicationException("Microsoft Word ist nicht installiert! Die Rechtschreibprüfung benötigt Microsoft Word.");
         }

         wordType.InvokeMember("Visible", BindingFlags.SetProperty | BindingFlags.OptionalParamBinding, null, wordApp, new object[1] { false });

         object words = documentType.InvokeMember("Words", BindingFlags.GetProperty | BindingFlags.OptionalParamBinding, null, document, new object[0]);
         object first = words.GetType().InvokeMember("First", BindingFlags.GetProperty | BindingFlags.OptionalParamBinding, null, words, new object[0]);

         first.GetType().InvokeMember("InsertBefore", BindingFlags.InvokeMethod | BindingFlags.OptionalParamBinding, null, first, new object[1] { text });
         documentType.InvokeMember("CheckSpelling", BindingFlags.InvokeMethod | BindingFlags.OptionalParamBinding, null, document, new object[0]);

         object characters = documentType.InvokeMember("Characters", BindingFlags.GetProperty | BindingFlags.OptionalParamBinding, null, document, new object[0]);
         object count = characters.GetType().InvokeMember("Count", BindingFlags.GetProperty | BindingFlags.OptionalParamBinding, null, characters, new object[0]);

         object firstChar = 0;
         object lastChar = (int)count - 1;

         object range = documentType.InvokeMember("Range", BindingFlags.InvokeMethod | BindingFlags.OptionalParamBinding, null, document, new object[2] { firstChar, lastChar });
         object correctedString = range.GetType().InvokeMember("Text", BindingFlags.GetProperty | BindingFlags.OptionalParamBinding, null, range, new object[0]);

         wordType.InvokeMember("Quit", BindingFlags.InvokeMethod | BindingFlags.OptionalParamBinding, null, wordApp, new object[1] { false });

         return correctedString as string;
      }

Rainbird Themenstarter:in
3.728 Beiträge seit 2005
vor 13 Jahren
Klasse

Hallo jaensen,

das sieht klasse aus. Sehr praktisch.

E
180 Beiträge seit 2010
vor 13 Jahren
Alternative

Unabhängig von installieren Officesystem kann Hunspell excelent genutzt werden. läuft schnell, stabil und es gibt genügend vorhandene Basiswörterbücher. Beispielapp ist auch enthalten 😃