UTF-8 String in RichTextBox anzeigen



  • In meinem Programm geht es u.a. darum, Dateinamen und andere Protokoll-Hinweise in einer RichTextBox anzuzeigen. Das mache ich mit

     richTextBox1.AppendText(Zeile + (Environment.NewLine));
    

    Wenn in "Zeile" ein Dateiname steht, der bestimmte Sonderzeichen enthält, dann werden diese nicht korrekt angezeigt

    Zeile = "Hase Handy💜 5€ Test.jpg"

    Das Herz-Symbol 💜 wird als Quadrat angezeigt.
    Intern ist alles OK, im Debugger sehe ich das Herz-Symbol.

    Muss man bei der RichTextBox irgendwo angeben, dass es sich bei dem Text um UTF-8 handelt ?
    Das €-Zeichen (Hex = E2 82 AC) wird korrekt angezeigt.

    Das 💜-Zeichen wird intern als folgender Hex-Code dargestellt: F0 9F 92 9C

    Wenn ich den Text aus der RichTextBox kopiere und in ein Edit-Fenster einfüge, wird dort wieder das Herz-Symbol angezeigt, es ist also korrekt in der RichTextBox gespeichert, wird nur nicht richtig angezeigt.

    Als Font habe ich Courier New eingestellt.



  • Die Winforms controls bei .Net können kein UTF-8 sondern nur UTF-16 (welches auch die default kodierung der klasse string ist)
    Daher UTF-8 -> UTF-16 konvertieren vor der anzeige.
    Allgemein kann die windows API nichts mit UTF-8 anfangen



  • @firefly ,
    Danke für den Hinweis.
    Ich benutze nun statt der RichTextBox ein ListView, da werden alle Zeichen korrekt dargestellt.



  • Und welchen Zeichensatz hast du da eingestellt? Ich denke, es liegt nur daran, daß der Zeichensatz ("Courier New") dieses Zeichen nicht enthält (und daher dann das Fallback-Zeichen, welches meistens ein Rechteck ist, darstellt).



  • @Th69 ,
    ListView zeigt auch bei Courier New diese Zeichen korrekt an.
    Ich habe auch noch andere Codes getestet, alle funktionieren.
    https://www.compart.com/de/unicode/U+1F49C
    Es wird schon so sein, wie firefly bereits sagte, dass die RichTextBox keine vollständige UTF-8 Unterstützung besitzt.



  • Was @firefly dir sagen wollte, ist, daß keines der Windows-Controls direkt UTF-8 Unterstützung bietet, sondern immer Strings im UTF-16 Encoding angegeben werden müssen.
    Die Darstellung von Zeichen ist immer eine Frage der Darstellung des eingestellten Zeichensatzes.

    Jedoch habe ich auch keine Erklärung, warum es bei der RichTextBox nicht funktioniert.
    Da müßtest du etwas mehr Code zeigen.



  • Ohne eine Lösung zu haben (auch abseits von UTF-8/16 und auch C#).

    @Th69 sagte in UTF-8 String in RichTextBox anzeigen:

    Und welchen Zeichensatz hast du da eingestellt? Ich denke, es liegt nur daran, daß der Zeichensatz ("Courier New") dieses Zeichen nicht enthält (und daher dann das Fallback-Zeichen, welches meistens ein Rechteck ist, darstellt).

    Nur ein schneller Test:
    https://i.imgur.com/gtKHqBy.png
    Links ein normales Editcontrol, rechts Richedit. Reinkopiert jeweils über die Zwischenablage, gleiche Schriftart eingewählt (lfStatusFont aus SystemParametersInfo).
    Dieses Verhalten hätte ich jetzt auch nicht erwartet.



  • Welche .NET-Version benutzt du? Ab Version 4.7 ist das wohl gefixt (es wurde vorher intern eine ältere Version des WinAPI RichEdit-Controls benutzt, s.a. RichTextBox cannot display Unicode Mathematical alphanumeric symbols).

    Falls du nicht upgraden kannst oder möchtest, so könntest du den Workaround benutzen (also ein eigenes davon abgeleitetes Control erstellen).



  • @hkdd sagte in UTF-8 String in RichTextBox anzeigen:

    Es wird schon so sein, wie firefly bereits sagte, dass die RichTextBox keine vollständige UTF-8 Unterstützung besitzt.

    Nö das hat mit UTF-8 gar nix zu tun. Windows tut immer mit UTF-16 und C# tut immer UTF-16. Und da UTF-8 und UTF-16 grundverschieden sind, liegt es sicher nicht daran dass du UTF-8 wo rein fütterst wo UTF-16 sein sollte. Sonst wäre jedes 2. Zeichen ein Kasterl.

    omit es vermutlich was zu tun hat ist der Rendering-Code der beiden Controls. Courier New & Co. haben lange nicht Glyphen für alles was Unicode so kann. Das normale Edit Control verwendet Funktionen wo Windows automatisch einen "Ersatzfont" auswählt um die fehlenden Zeichen auszugeben.

    Vermutung: Da das Richedit Control aber mehr "kann" (unterschiedliche Formatierung einzelner Wörter/Zeichen etc.), muss es mehr selbst machen. Daher kann es die einfachen Text-Ausgabefunktionen (wo Windows die ganze Show vonwegen Ersatzfont suchen erledigt) nicht verwenden. Weil man bei denen nur einen Font/Grösse/Farbe etc. für alles angeben kann. Und da es keinen eigenen Code für Ersatzfont Suchen hat, wird alles was im ausgewählten Font fehlt einfach als Kasterl angezeigt.



  • Ich habe jetzt noch etwas mit Delphi 10.3 getestet.
    Da wird in einem TRichEdit-Fenster auch nur ein Quadrat, statt Herz angezeigt und in einem TListBox-Fenster ist alles OK.
    Der gleiche Effekt, wie von @yahendrik auch für C# festgestellt.
    Die Strings sind immer UTF8.


  • Administrator

    @hkdd sagte in UTF-8 String in RichTextBox anzeigen:

    Die Strings sind immer UTF8.

    Mich würde ja mal interessieren, wie du weisst, dass es sich um UTF-8 handelt. Die Enkodierung ist vielfach so transparent, dass du gar nicht mitbekommst, dass sich diese irgendwo ändert. Schliesse mich Th69 und hustbaer an. Das hat nichts mit UTF-8 oder UTF-16 zu tun.



  • Ich habe jetzt selber mal den von mir beschriebenen Workaround (ExRichText) mit einem kleinen C# WinForms Programm ausprobiert und zumindestens unter Win10 funktioniert es (während die .NET 4 RichTextBox das Herzchen wirklich nicht richtig anzeigt).

    Unter Win7 wird das Zeichen jedoch von keinem Standardcontrol (auch nicht dem Editor/TextBox) angezeigt, also nur als Rechteck dargestellt.
    Jedoch wird es vom VS 2015 korrekt im Texteditor dargestellt!

    @hkdd: Unsere Aussagen bzgl. UTF-8 und UTF-16 hast du anscheinend immer noch begriffen?!



  • @Th69 ,
    offenbar habe ich da etwas falsch angenommen.
    Zumindest die CS-Codedateien mit dem VS-Editor bearbeitet, haben das UTF8-Format und am Anfang auch einen UTF8-BOM = EF BB BF.
    Das Standard-string-Format ist UTF-16 = Unicode, wie hier ganz klar genannt:
    https://docs.microsoft.com/de-de/dotnet/standard/base-types/character-encoding

    Wenn man mit dieser Faktenlage sich überlegt, warum eine string-Variable, die das Herz-Symbol korrekt enthält (im Unicode-Zeichensatz), die man in ein string[]-Array einer RichTextBox, welches ja demnach auch im Unicode-Format dargestellt sein sollte, in der RichTextBox nicht als Herz-Symbol dargestellt wird.
    Demnach ist string nicht immer gleich string. Oder doch ?



  • @hkdd sagte in UTF-8 String in RichTextBox anzeigen:

    Demnach ist string nicht immer gleich string. Oder doch ?

    String ist String. Encoding ist Encoding.



  • @Swordfish
    Das Encoding läuft dabei unaufgefordert ab.
    Ich habe mal ein ganz kleines Testprogramm gemacht

    using System;
    using System.IO;
    namespace StringTest
    {
        class Program
        {
            static void Main(string[] args)
            {
                StreamWriter Ausgabe = new StreamWriter(@"L:\StringTest.txt");
                Ausgabe.WriteLine("H💜E€");
                Ausgabe.Close();
                Environment.Exit(0);
            }
        }
    }
    

    Da ist kein Encoding drin. Von UTF8 ist auch nirgendwo die Rede.
    Die erstellte Datei sieht folgendermaßen aus:

    H💜E€
    

    Und im Hex-Listing..

     48 F0 9F 92  9C 45 E2 82  AC 0D 0A    
    

    "H" = 0x48
    "💜" = 0xF0 9F 92 9C
    "E" = 0x45
    "€" = 0xE2 82 AC
    0D 0A ist der Zeilenabschluss.

    Es handelt sich eindeutig um UTF8 (ohne BOM).



  • @Th69 sagte in UTF-8 String in RichTextBox anzeigen:

    Welche .NET-Version benutzt du? Ab Version 4.7 ist das wohl gefixt

    das könnte die Ursache sein (werde ich probieren).
    Ich benutze für bestimmte Programme die 4 (nicht 4.7),
    weil nur dadurch diese Programme auch unter XP funktionieren.



  • Dann nimm den von mir oben beschriebenen Workaround (jedoch wird das Herzchen dann wohl auch nicht unter XP angezeigt werden, wenn es schon nicht für Win7 klappt).

    Mit welcher Windows-Version hast du es denn erstellt und getestet?

    Und beim StreamWriter ist UTF-8 das Standard-Encoding (wenn man es nicht explizit angibt), aber ohne BOM: StreamWriter(string) (s. Hinweise)
    So gesehen liefert dein Testprogramm jetzt nichts Interessantes.


  • Administrator

    @hkdd Die dotNet String Klasse verwendet intern UTF-16. Der StreamWriter schreibt standardmässig mit UTF-8. Findest du in der Dokumentation:

    This constructor creates a StreamWriter with UTF-8 encoding without a Byte-Order Mark (BOM), so its GetPreamble method returns an empty byte array.

    Das Problem ist die Darstellung und diese wird von Fonts und Controls übernommen. Und es gibt viele unterschiedliche Arten von Fonts. Und gewisse Controls können mit gewissen Fonts oder spezifischen Zeichen nicht umgehen. Daher hat dies nichts mit Enkodierung oder Unicode zu tun. Hier geht es nur um die Darstellung.

    UTF-8, UTF-16 und UTF-32 sagen nichts über die Darstellung aus. Das sind ausschliesslich Definitionen, wie die rohen Textdaten (also Code points) gespeichert werden sollen.



  • @Th69 sagte in UTF-8 String in RichTextBox anzeigen:

    Mit welcher Windows-Version hast du es denn erstellt und getestet?

    Mit Win10-Pro-64 1903



  • @Dravere sagte in UTF-8 String in RichTextBox anzeigen:

    @hkdd Die dotNet String Klasse verwendet intern UTF-16. Der StreamWriter schreibt standardmässig mit UTF-8. Findest du in der Dokumentation:

    This constructor creates a StreamWriter with UTF-8 encoding without a Byte-Order Mark (BOM), so its GetPreamble method returns an empty byte array.

    Das Problem ist die Darstellung und diese wird von Fonts und Controls übernommen. Und es gibt viele unterschiedliche Arten von Fonts. Und gewisse Controls können mit gewissen Fonts oder spezifischen Zeichen nicht umgehen. Daher hat dies nichts mit Enkodierung oder Unicode zu tun. Hier geht es nur um die Darstellung.

    UTF-8, UTF-16 und UTF-32 sagen nichts über die Darstellung aus. Das sind ausschliesslich Definitionen, wie die rohen Textdaten (also Code points) gespeichert werden sollen.

    Das ist richtig. Nur soweit ich weis ist UTF-8 Support in .Net selbst für Controls nicht vorgesehen sonder UTF-16 (Das ist die standard UNICODE Kodierung von Windows)
    Daher sollte man das ganze nochmal prüfen, wenn man den UTF-8 String (Der bestimmt nicht als C# String vorhanden ist, da die String klasse UTF-16 verwendet) nach UTF-16 konvertiert wird bevor es dem Control übergeben wird


Anmelden zum Antworten