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:
object wordApp;
wordApp=SpellChecker.StartWinword();
IList<string> wrongWords=SpellChecker.CheckSpelling("Hallo Welt!",wordApp);
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
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
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.
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.
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
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;
}
Hallo jaensen,
das sieht klasse aus. Sehr praktisch.
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 😃