2016-03-18 2 views
5

Ich portiere eine Anwendung für Autoren auf die UWP-Plattform. Das einzige Puzzleteil, das ich noch habe, ist die NHunspell-Bibliothek. Ich benutze es ausgiebig für Rechtschreibprüfung und Thesaurus-Funktionen. Ich habe es ganz individuell gestaltet und benutzerdefinierte Wörterbücher für verschiedene Dinge erstellt (d. H. Ein anderes Wörterbuch für jedes Schreibprojekt). Diese Bibliothek ist eine schöne Sache.Rechtschreibbibliotheken (wie hunspell) in UWP-Anwendungen?

Allerdings kann ich nicht scheinen, diese DLL in meine UWP-Anwendung einzuschließen.

1) Gibt es eine Möglichkeit, die Verwendung dieser DLL zu erzwingen? Ich mag es wirklich, wie das NHunSpell-System eingerichtet ist. Es macht gesunden Menschenverstand und ist sehr schnell und einfach zu bedienen.

2) Wenn nicht, kann jemand eine bessere Lösung für benutzerdefinierte Wörterbücher, angepasste Rechtschreibprüfung usw. empfehlen?

Update 3

Nach umfangreicher Aktualisierung und Online-Lesen, fand ich einen Link, um die Theorie der Rechtschreibprüfung zu diskutieren. Hier ist ein kurzes Beispiel (dasjenige, das ich am meisten benutzt habe).

http://www.anotherchris.net/csharp/how-to-write-a-spelling-corrector-in-csharp/

Nach dem Lesen dieses Artikels, dass die Basiscode nehmen, und die englischen Wörter aus den Hunspell .dic Dateien Strippen, ich habe meine eigene Rechtschreibprüfung Bibliothek erstellt, die in UWP funktioniert.

Sobald ich es verfestigt habe, werde ich es als Antwort unten posten, um an die SO-Community zu spenden. :)

aktualisieren 2

ich die Verwendung von Hunspell Gegentor. Es sieht nicht so aus, als wäre es überhaupt möglich ... Gibt es noch andere Bibliotheken/Pakete, die jemand vorschlagen kann?

UPDATE:

Ich brauche wohl die Anweisung neu zu formulieren, dass ich nicht die DLL enthalten kann: Ich kann die DLL durch NuGet umfassen. Es beschwert sich, dass die DLL nicht mit der UAP/UWP-Plattform kompatibel ist.

Ich bin in der Lage, MANUELL die DLL in meinem Projekt durch Verknüpfung mit einer vorhandenen DLL (nicht NuGet). Diese DLL erweist sich jedoch als inkompatibel mit der UAP-Plattform. Ein einfacher Aufruf zur Rechtschreibprüfung eines Wortes funktioniert in WinForms einwandfrei, stürzt jedoch sofort mit System.IO.FileNotFoundException ab.

Der Konstruktor von NHunspell reicht aus, um die zugehörigen Dateien .dic und .aff zu laden. Allerdings habe ich dies gemildert, indem ich die Dateien in den Speicher geladen habe und dann den alternativen Konstruktor aufgerufen habe, der für jede dieser Dateien ein Byte-Array anstelle eines Dateinamens verwendet. Es stürzt immer noch, aber mit einem neuen Method not found Fehlern:

String System.AppDomain.get_RelativeSearchPath()

ich für jede Rechtschreibprüfung Motor suchen, die innerhalb des UAP Rahmen arbeiten. Ich würde es vorziehen NHunspell einfach aus Gründen der Vertrautheit zu sein. Ich bin jedoch nicht blind dafür, dass dies als Option immer weniger möglich wird.

Leute, mit denen ich arbeite, haben vorgeschlagen, dass ich die integrierten Rechtschreiboptionen verwende.Ich kann jedoch nicht die integrierten Rechtschreibprüfungsfunktionen von Windows 10/TextBox verwenden (die ich kenne), weil ich benutzerdefinierte Wörterbücher nicht steuern kann und Dinge wie automatische Großschreibung und Ersetzen von Wörtern (wo es ersetzt das Wort für Sie, wenn es denkt, dass es nah genug an der richtigen Schätzung ist). Diese Dinge sind Kapitelselbstmord für Schriftsteller! Ein Schreiber kann sie auf Betriebssystemebene deaktivieren, aber sie können sie für andere Apps verwenden, nur nicht für dieses.

Bitte lassen Sie mich wissen, wenn es eine Ausweichmöglichkeit für NHunspell gibt. Und wenn Sie keine Lösung kennen, lassen Sie mich Ihre beste benutzerdefinierte Rechtschreibprüfungs-Engine wissen, die innerhalb des UAP-Frameworks funktioniert.

Als Randbemerkung verwende ich NHunspell für seine Thesaurus-Fähigkeit. Es funktioniert sehr gut in meinen Windows-Apps. Ich müsste diese Funktionalität auch ersetzen - hoffentlich mit der gleichen Engine wie die Rechtschreibprüfungs-Engine. Allerdings, wenn Sie eine gute Thesaurus-Engine wissen (aber es Rechtschreibprüfung), das ist auch gut!

Vielen Dank !!

+0

Können Sie weitere Details angeben? Bauen Sie aus der Quelle? –

+0

Ich habe den NHunspell nicht aus der Quelle gebaut. In früheren Versionen (nicht UWP) habe ich NHunspell aus NuGet-Paketen verwendet. Mit meiner UWP-App sagt mir NuGet, dass NHunspell nicht kompatibel ist. – Jerry

+0

NuGet ist richtig, Sie müssen die Bibliothek aus Quellcode mit dem UWP SDK erstellen. – yms

Antwort

3

ich herunterladen, den Quellcode NHunspell Bibliothek und ich versuchte, eine Bibliothek mit UWP Unterstützung zu bauen, jedoch fand ich Probleme mit der Rangierung (Marshalling.cs)
Das Paket lädt DLLs, die nur in x86 und x64 Arbeits Architektur, so in Arm (Handys, Tabletten) wird die App nicht funktionieren.
Die Pakete Lasten dlls mit Systemaufrufen:

[DllImport("kernel32.dll")] 
    internal static extern IntPtr LoadLibrary(string fileName); 

und ich denke, dass es für die Arbeit in UWP umschreiben muss, weil UWP eine Sandbox verwendet.

IMHO gibt es nur zwei Optionen:
1) Umschreiben Sie die Marshalling-Klasse mit den Einschränkungen von UWP.
2) Verwenden Sie Hunspell nicht in Ihrem Programm.

Ich habe kein großes Wissen über dlls mit UWP, aber ich glaube, dass das Neuschreiben sehr schwierig sein könnte.

+0

Ich bin sehr dankbar für Ihren Versuch! Danke für die Erklärung. Tolle Erklärung. Kennen Sie ein anderes Paket als nhunspell für Rechtschreibung und Thesaurus? Ich habe eine Suche online durchgeführt und nichts nützliches gefunden. (viele Verweise auf andere Pakete wie apsell, aber keine von denen wird auch in UWP funktionieren) – Jerry

+0

Sorry, aber ich habe keine andere Bibliothek gefunden, die nhunspell ersetzen kann. Ich denke jedoch, dass Sie ein Web mit nhunspell entwickeln können und dann können Sie eine Web-gehostete UWP erstellen. Vielleicht kann dies das Problem lösen – ganchito55

+0

Kein Problem. Siehe mein letztes Update. Ich schätze Ihre Eingabe jedoch sehr. – Jerry

1

Wie versprochen, hier ist die Klasse, die ich gebaut habe, um meine Rechtschreibprüfung durchzuführen.

using System; 
using System.Collections.Generic; 
using System.IO; 
using System.Linq; 
using System.Text; 
using System.Text.RegularExpressions; 
using System.Threading.Tasks; 

namespace Com.HanelDev.HSpell 
{ 
    public class HSpellProcess 
    { 
     private Dictionary<string, string> _dictionary = new Dictionary<string, string>(); 

     public int MaxSuggestionResponses { get; set; } 

     public HSpellProcess() 
     { 
      MaxSuggestionResponses = 10; 
     } 

     public void AddToDictionary(string w) 
     { 
      if (!_dictionary.ContainsKey(w.ToLower())) 
      { 
       _dictionary.Add(w.ToLower(), w); 
      } 
      else 
      { 
       // Upper case words are more specific (but may be the first word 
       // in a sentence.) Lower case words are more generic. 
       // If you put an upper-case word in the dictionary, then for 
       // it to be "correct" it must match case. This is not true 
       // for lower-case words. 
       // We want to only replace existing words with their more 
       // generic versions, not the other way around. 
       if (_dictionary[w.ToLower()].CaseSensitive()) 
       { 
        _dictionary[w.ToLower()] = w; 
       } 
      } 
     } 

     public void LoadDictionary(byte[] dictionaryFile, bool resetDictionary = false) 
     { 
      if (resetDictionary) 
      { 
       _dictionary = new Dictionary<string, string>(); 
      } 
      using (MemoryStream ms = new MemoryStream(dictionaryFile)) 
      { 
       using (StreamReader sr = new StreamReader(ms)) 
       { 
        string tmp = sr.ReadToEnd(); 
        tmp = tmp.Replace("\r\n", "\r").Replace("\n", "\r"); 
        string [] fileData = tmp.Split("\r".ToCharArray()); 

        foreach (string line in fileData) 
        { 
         if (string.IsNullOrWhiteSpace(line) || line.StartsWith("#")) 
         { 
          continue; 
         } 

         string word = line; 

         // I added all of this for file imports (not array imports) 
         // to be able to handle words from Hunspell dictionaries. 
         // I don't get the hunspell derivatives, but at least I get 
         // the root word. 
         if (line.Contains("/")) 
         { 
          string[] arr = line.Split("/".ToCharArray()); 
          word = arr[0]; 
         } 

         AddToDictionary(word); 
        } 
       } 
      } 
     } 

     public void LoadDictionary(Stream dictionaryFileStream, bool resetDictionary = false) 
     { 
      string s = ""; 
      using (StreamReader sr = new StreamReader(dictionaryFileStream)) 
      { 
       s = sr.ReadToEnd(); 
      } 

      byte [] bytes = Encoding.UTF8.GetBytes(s); 

      LoadDictionary(bytes, resetDictionary); 
     } 

     public void LoadDictionary(List<string> words, bool resetDictionary = false) 
     { 
      if (resetDictionary) 
      { 
       _dictionary = new Dictionary<string, string>(); 
      } 

      foreach (string line in words) 
      { 
       if (string.IsNullOrWhiteSpace(line) || line.StartsWith("#")) 
       { 
        continue; 
       } 

       AddToDictionary(line); 
      } 
     } 

     public string ExportDictionary() 
     { 
      StringBuilder sb = new StringBuilder(); 

      foreach (string k in _dictionary.Keys) 
      { 
       sb.AppendLine(_dictionary[k]); 
      } 

      return sb.ToString(); 
     } 

     public HSpellCorrections Correct(string word) 
     { 
      HSpellCorrections ret = new HSpellCorrections(); 
      ret.Word = word; 

      if (_dictionary.ContainsKey(word.ToLower())) 
      { 
       string testWord = word; 
       string dictWord = _dictionary[word.ToLower()]; 
       if (!dictWord.CaseSensitive()) 
       { 
        testWord = testWord.ToLower(); 
        dictWord = dictWord.ToLower(); 
       } 

       if (testWord == dictWord) 
       { 
        ret.SpelledCorrectly = true; 
        return ret; 
       } 
      } 

      // At this point, we know the word is assumed to be spelled incorrectly. 
      // Go get word candidates. 
      ret.SpelledCorrectly = false; 

      Dictionary<string, HSpellWord> candidates = new Dictionary<string, HSpellWord>(); 

      List<string> edits = Edits(word); 

      GetCandidates(candidates, edits); 

      if (candidates.Count > 0) 
      { 
       return BuildCandidates(ret, candidates); 
      } 

      // If we didn't find any candidates by the main word, look for second-level candidates based on the original edits. 
      foreach (string item in edits) 
      { 
       List<string> round2Edits = Edits(item); 

       GetCandidates(candidates, round2Edits); 
      } 

      if (candidates.Count > 0) 
      { 
       return BuildCandidates(ret, candidates); 
      } 

      return ret; 
     } 

     private void GetCandidates(Dictionary<string, HSpellWord> candidates, List<string> edits) 
     { 
      foreach (string wordVariation in edits) 
      { 
       if (_dictionary.ContainsKey(wordVariation.ToLower()) && 
        !candidates.ContainsKey(wordVariation.ToLower())) 
       { 
        HSpellWord suggestion = new HSpellWord(_dictionary[wordVariation.ToLower()]); 

        suggestion.RelativeMatch = RelativeMatch.Compute(wordVariation, suggestion.Word); 

        candidates.Add(wordVariation.ToLower(), suggestion); 
       } 
      } 
     } 

     private HSpellCorrections BuildCandidates(HSpellCorrections ret, Dictionary<string, HSpellWord> candidates) 
     { 
      var suggestions = candidates.OrderByDescending(c => c.Value.RelativeMatch); 

      int x = 0; 

      ret.Suggestions.Clear(); 
      foreach (var suggest in suggestions) 
      { 
       x++; 
       ret.Suggestions.Add(suggest.Value.Word); 

       // only suggest the first X words. 
       if (x >= MaxSuggestionResponses) 
       { 
        break; 
       } 
      } 

      return ret; 
     } 

     private List<string> Edits(string word) 
     { 
      var splits = new List<Tuple<string, string>>(); 
      var transposes = new List<string>(); 
      var deletes = new List<string>(); 
      var replaces = new List<string>(); 
      var inserts = new List<string>(); 

      // Splits 
      for (int i = 0; i < word.Length; i++) 
      { 
       var tuple = new Tuple<string, string>(word.Substring(0, i), word.Substring(i)); 
       splits.Add(tuple); 
      } 

      // Deletes 
      for (int i = 0; i < splits.Count; i++) 
      { 
       string a = splits[i].Item1; 
       string b = splits[i].Item2; 
       if (!string.IsNullOrEmpty(b)) 
       { 
        deletes.Add(a + b.Substring(1)); 
       } 
      } 

      // Transposes 
      for (int i = 0; i < splits.Count; i++) 
      { 
       string a = splits[i].Item1; 
       string b = splits[i].Item2; 
       if (b.Length > 1) 
       { 
        transposes.Add(a + b[1] + b[0] + b.Substring(2)); 
       } 
      } 

      // Replaces 
      for (int i = 0; i < splits.Count; i++) 
      { 
       string a = splits[i].Item1; 
       string b = splits[i].Item2; 
       if (!string.IsNullOrEmpty(b)) 
       { 
        for (char c = 'a'; c <= 'z'; c++) 
        { 
         replaces.Add(a + c + b.Substring(1)); 
        } 
       } 
      } 

      // Inserts 
      for (int i = 0; i < splits.Count; i++) 
      { 
       string a = splits[i].Item1; 
       string b = splits[i].Item2; 
       for (char c = 'a'; c <= 'z'; c++) 
       { 
        inserts.Add(a + c + b); 
       } 
      } 

      return deletes.Union(transposes).Union(replaces).Union(inserts).ToList(); 
     } 

     public HSpellCorrections CorrectFrom(string txt, int idx) 
     { 
      if (idx >= txt.Length) 
      { 
       return null; 
      } 

      // Find the next incorrect word. 
      string substr = txt.Substring(idx); 
      int idx2 = idx; 

      List<string> str = substr.Split(StringExtensions.WordDelimiters).ToList(); 

      foreach (string word in str) 
      { 
       string tmpWord = word; 

       if (string.IsNullOrEmpty(word)) 
       { 
        idx2++; 
        continue; 
       } 

       // If we have possessive version of things, strip the 's off before testing 
       // the word. THis will solve issues like "My [mother's] favorite ring." 
       if (tmpWord.EndsWith("'s")) 
       { 
        tmpWord = word.Substring(0, tmpWord.Length - 2); 
       } 

       // Skip things like ***, #HashTagsThatMakeNoSense and 1,2345.67 
       if (!tmpWord.IsWord()) 
       { 
        idx2 += word.Length + 1; 
        continue; 
       } 

       HSpellCorrections cor = Correct(tmpWord); 

       if (cor.SpelledCorrectly) 
       { 
        idx2 += word.Length + 1; 
       } 
       else 
       { 
        cor.Index = idx2; 
        return cor; 
       } 
      } 

      return null; 
     } 
    } 
} 
0

Sie können die integrierte Rechtschreibprüfung von Windows direkt verwenden, damit Sie das Verhalten besser steuern können. Und dann wenden Sie Ihre Ergebnisse selbst auf das Textbox-Steuerelement an.

Werfen Sie einen Blick auf ISpellChecker. Es gibt Ihnen add Ihr eigenes Benutzerwörterbuch und hat viel mehr Optionen, um sein Verhalten zu steuern. Und ja, es ist für UWP verfügbar.

+0

Interessante Idee. Ich habe das schon einmal gesehen, aber ich habe zwei große Bedenken. 1) Microsoft hat sich sehr bemüht, diese Schnittstelle in ihrer Dokumentation als "Nicht verwenden" zu markieren. Keine große Sache, aber macht mir Sorgen und 2) Noch wichtiger, auch wenn ich das erstellt habe, habe ich keine spezielle Methode gefunden, meiner App zu sagen, dass sie die * MY * Rechtschreib-Klasse anstelle der integrierten Rechtschreib-Klasse verwenden soll. – Jerry

+0

Die Dokumentation sagt "nicht implementieren", nicht "nicht verwenden". Das ist ein großer, großer Unterschied! – Stefan

+0

Nicht sicher, wofür du deine eigene Rechtschreibprüfung "Klasse" brauchst - damit brauchst du keine. https://msdn.microsoft.com/en-us/library/windows/desktop/hh869748%28v=vs.85%29.aspx und hier ist ein Beispiel: https://code.msdn.microsoft.com/windowsdesktop/Rechtschreibprüfung-Client-aea0148c – Stefan

Verwandte Themen