none
String säubern aber wie? RRS feed

  • Frage

  • Ich habe von einer App den Sourcecode übernommen und versuche die App weiter zu entwickeln. Das klappt soweit recht gut. Aktuell stolpere ich aber über ein für mich unlösbares Problem. Die App ließt eine Datenbank aus. Hier sind verschlüsselte und unverschlüsselte Strings enthalten. Die Entschlüsselung klappt gut, das ist auch nicht das Problem. Die Strings landen in Textfeldern. Von hier aus, kann ich die Strings in die Zwischenablage kopieren und dann in anderen Apps einfügen. Beim Einfügen habe ich aber bemerkt das mehr kopiert wird, als ich im Ursprungstextfeld sehe. Beispiel: In Textfeld A steht in meiner App der String "D78fjghjduFG". Das markiere ich und kopiere es in das Clipboard mit Clipboard.SetText(Textfeld.Text); Nun gehe ich in eine andere App und füge den Text der Zwischenablage ein. Ich sehe nun die Zeichenkette "D78fjghjduFG" gefolgt von irgendwelchen chinesisch aussehenden Zeichen. Füge ich die Zwischenablage erneut ein, bleibt der String gleich, die "chinesischen Zeichen" ändern sich aber. Was ist das für Zeug und wie kann ich das ausfiltern?
    Freitag, 20. Februar 2015 19:13

Antworten

  • Das mit dem Nullterminator an einen byte[] array anzuhängen geht über viele Wege. Bei deinen kleinen Arrays wäre es einfach, das Array zu kopieren und dort das neue Element anzuhängen.

    Beispiel:

    /*
    * Fügt an ein byte[]-Array einen Null-Terminator an.
    */
    byte[] AppendNullTermninator(byte[] predata) {
         const byte nullT = (byte)'\0';
    
         int max = predata.Length;
         byte[] res = new byte[max + 1]; //Neues, um ein Element vergrößertes Array anlegen
    
         /* Dieser Teil hätte auch mit einer For-Schleife gemacht werden können */
         int i = 0; //Zähler
         while (i < max) {
              res[i] = predata[i]; //Stück für Stück kopieren
              i++;
         }
    
         res[max] = nullT;
         return res;
    }
    Und wegen der Benutzung von VS: Du kannst doch, wenn du eine Stelle hat, wo der Stirng zusammengesetzt wird, einen BreakPoint dort erstellen und dir dann in einem der unteren Anzeigefenster, habe gerade den Namen vergessen, den Inhalt der Variablen anschauen.


    © 2015 Thomas Roskop

    Germany // Deutschland


    Sonntag, 22. Februar 2015 15:32

Alle Antworten

  • Hallo Sebastian,

    poste doch bitte den Quellcode, den Du verwendest, sowohl zum kopieren als auch zum einfügen.

    Dazu wäre es sicher hilfreich, wenn Du mal den Debugger anschmeißt und vor dem Kopieren einen Breakpoint setzt. Dort schaust Du dir an, was genau in deinem Textfeld steht und ob sich das wirklich von dem unterscheidet, was in der Zwischenablage zu sehen ist. Hier solltest Du dir den Inhalt im Hexformat oder zumindest als Char Array ansehen.

    Ggfs. steht \0 in der Zeichenfolge, was in der Regel dazu führt, dass der sichtbare String dort endet. Bei einer programmatischen Vearbeitung ist der Variableninhalt aber vollständig.


    Gruß, Stefan
    Microsoft MVP - Visual Developer ASP/ASP.NET
    http://www.asp-solutions.de/ - Consulting, Development
    http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community

    Freitag, 20. Februar 2015 19:30
    Moderator
  • Hallo Sebastian, kann es sein, dass die App in c++ ist?

    Diese seltsamen Zeichen zeigen normalerweise, vor allem wenn sie immer anders sind, an, dass der String nicht korrekt beendet wurde. Jeder String besteht aus einer reihe von Zeichen und dem letztem Zeichen, einem '\0' (Nul-Terminator). 

    Wenn dieser Fehler, weiß das System nicht wann stopp ist, und denkt einfach, der Rest wäre auch ein String und gibt ihn mit aus, bis der nächste, zufällige, Terminator kommt.

    Dies ist normalerweise ein Zeichen dafür, dass du beim Einlesen die falsche Länge genommen hast. Versuche doch einfach, diesen ans Ende des Strings anzuhängen, sollte klappen.

    PS: Das zeichen kannst du auch wie folgt erstellen:

    //c++
    char terminator = '\0';
    
    //c#
    string mystring;
    //...
    mystring += '\0'; //Ist bei c# eigentlich nicht notwendig.


    © 2015 Thomas Roskop

    Germany // Deutschland


    Freitag, 20. Februar 2015 19:34
  • Würde das nicht heißen, ich müsste nach \0 nur alles folgende abschneiden?Kopieren tu ich mit:

    Clipboard.SetText(Textbox.Text);

    danach lasse ich mir die Länge auslesen mit

    var leng = Textbox.Text.Length;

    und mir beides ausgeben:

    MessageBox.Show("Länge: " + leng + " Zeichen"  + "\n" + "Text: " + Textbox.Text);

    In der Messagebox sehe ich nun die korrete Länge und den korrekten String. Füge ich es aber in der anderen App ein, habe ich Blödsinn am Ende dran hängen.

    Vielleicht noch eines. Meine App ist mit Visual Studio 2010 für WIndows Phone 7.x erstellt, sie wird aber auf einem WP8 Phone deployed. Ich füge den Text dann in einer Textbox einer Windows Store App für WIndows Phone 8.1 ein. Einfügen tu ich den String nicht mit Programmcode, sondern per Button auf der virtuellen Tastatur.

    Füge ich den String im Mailprogramm ein, kopiere ihn erneut in die Zwischenablage (manuell) und füge ihn dann in der Textbox ein, ist der String OK.

    Freitag, 20. Februar 2015 19:44
  • Hallo Sebastian,

    dann würde drauf tippen, dass deine Daten aus der Datenbank nicht im UTF-16 Format vorliegen und es daher zu Datenmischmasch kommt.

    Da keine automatische Konvertierung stattfindet, wird dann wohl das genommen, was da ist und wenn das Ascii, UTF-8, ... ist passt es eben nicht. Siehe dazu auch:

      https://msdn.microsoft.com/de-de/library/windows/apps/ms597043.aspx

    Falls dem so ist, müsstest Du die Daten vor dem Aufruf von SetText manuell konvertieren. Dazu musst Du aber die aktuelle Codierung kennen.

      https://msdn.microsoft.com/de-de/library/windows/apps/kdcak6ye.aspx

    Ich bin allerdings nicht sicher, ob die Methoden zum Konvertieren in WP 7 zur Verfügung stehen.


    Gruß, Stefan
    Microsoft MVP - Visual Developer ASP/ASP.NET
    http://www.asp-solutions.de/ - Consulting, Development
    http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community


    Freitag, 20. Februar 2015 22:12
    Moderator
  • Nunja, ich habe kein Problem damit die App nach Windows Phone zu konvertieren, dort soll sie am Ende ja auch laufen. Ich habe diesen Schritt bisher gescheut, das ich nur Windows Vista und Windows 7 Rechner zur Verfügung habe und ich damit keine Windows Phone 8 Apps entwicklen kann. Ich komme nur selten an einen Windows 8 Rechner um die App testweise zu deployen.

    OK aber den Tipp mal weitergesponnen: Wie kriege ich denn raus, welches Encoding der String eigentlich hat? Mit

    var EncTest = Encoding.GetEncoding(txtPassword.Text).GetType();
    MessageBox.Show("Encoding: " + EncTest);
    bin ich nicht weit gekommen :-(
    Samstag, 21. Februar 2015 12:33
  • Hallo Sebastian,

    das bekommst Du nicht wirklich raus, das muss man einfach wissen.

    Du solltest dir also mal die Anwendung anschauen, die die Daten in die Datenbank schreibt. Dort kannst Du evtl. auch sehen, welches Encoding verwendet wurde.

    Es gibt zwar verschiedene Ansätze, das Encoding zu ermitteln, die sind aber auch nicht 100%ig, evtl. hilfts dir ja aber:

      https://www.google.de/#q=c%23+detect+encoding


    Gruß, Stefan
    Microsoft MVP - Visual Developer ASP/ASP.NET
    http://www.asp-solutions.de/ - Consulting, Development
    http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community

    Samstag, 21. Februar 2015 13:18
    Moderator
  • Ich weiß, ganz anderer ANsatz aber ich hab grad gemerkt, das ich mir sauber den ersten und letzten Character ermiitel kann. Also werd ich das Teil in seine Char zerlegen und wieder zusammensetzen. Sollte ja vermutlich reichen und auch unter WP7 und 8 funktionieren.

    Mit folgendem, sicherlich umständlichen Construct klappt es:

    var pwlength = Textbox.Text.Length -1;
    char[] testArr = new char[Textbox.Text.Length];
    
                for (int i = 0; i < pwlength; i++)
                {
                    testArr[i] = Textbox.Text[i];
                }
    
                string s = new string(testArr);
    
                Clipboard.SetText(s);
    Mit theString.ToCharArray(); hat es nicht geklappt.


    • Bearbeitet Manfred P Samstag, 21. Februar 2015 13:56
    Samstag, 21. Februar 2015 13:38
  • toll :( zu früh gefreut. Kopiere ich einzelne Zeichen ins Clipboard, sind die sauber. Baue ich daraus wieder einen String, hab ich den Müll wieder drin. ALso muss ich weiter suchen...
    Samstag, 21. Februar 2015 21:54
  • Hallo Sebastian,

    Du müsstest wahrscheinlich nicht mehr suchen, wenn Du dich drum kümmern würdest, mit welchem Encoding die Daten geschrieben wurden. Dann kannst Du die Codierung entsprechend ändern und es sollte laufen.

    (Man kann sich das Leben aber auch selbst schwer machen, wenn man das unbedingt will)


    Gruß, Stefan
    Microsoft MVP - Visual Developer ASP/ASP.NET
    http://www.asp-solutions.de/ - Consulting, Development
    http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community

    Samstag, 21. Februar 2015 22:59
    Moderator
  • Das würde ich ja gerne herausfinden aber leider weiß ich es nicht. Laut Entwickler der Original App, werden die Einträge in UTF-8 gespeichert (und ich habe keinen Grund an dieser Aussage zu zweifeln). Meine Third-Party-App, deren Sourcen ich übernommen habe, kümmern sich um das Auslesen der Daten. Wie, das habe ich nicht verstanden. Ich fange grad erst mit den ersten Gehversuchen an und baue die GUI um und ein paar neue Funktionen ein. Das klappt auch bisher recht gut. Das Problem mit den Zeichen hat aber nicht nur meine Version, sondern auch die Originalversion. Ich wollte das nun lediglich bereinigen. Schelcht, wenn ich nicht verstehe, was dort genau passiert.

    Konvertiere ich nun von UTF-8 nach Unicode habe ich den gleichen Datenmüll noch immer im String. Es ändert sich nichts. Lese ich den String einfach aus, habe ich ebenfalls den Datenmüll drinnen. Unter WIndows Phone 7 habe ich das Problem generell nicht. Keine Ahnung, ob sich in Hinblick auf Encoding etwas zwischen WP7 und WP8 geändert hat. Gelesen habe ich bisher nichts darüber. Mag sein, das ich es mir schwer mache aber mir gehen langsam die Ideen aus. Soweit ich sehen kann, hab ich auch nur Encoding.Unicode und Encoding.UTF8 zur Verfügung unter WP8. Mehr wird mit nicht angeboten... Alles was ich mache, ist learning-by-doing. Sorry...

    Sonntag, 22. Februar 2015 12:37
  • Hallo,

    zu erst einmal solltest du Unicode nicht mit UTF-8 verwechseln, das würde einen großen Fehler ausmachen. Unicode definiert die Codepunkte, also welches Zeichen welchen Wert hat, UTF-8 die Art und weise, wie die Werte in Dateiennetc. gespeichert werden -> großer Unterschied, nicht mischen!!!

    Du solltest versuchen, den Datensatz, den du hast, mittels der GetString(byte[]) methode zu lesen.

    Wenn der Datensatz auch wirklich mittels GetBytes(string s) geschrieben wurde, so sollte dies kein Problem sein.


    © 2015 Thomas Roskop

    Germany // Deutschland

    Sonntag, 22. Februar 2015 12:44
  • OK, ich hab jetz folgendes gemacht aber habe wieder den Müll dabei:

    string contents = null; Encoding utf8 = Encoding.UTF8;
    Byte[] bytes = new Byte[Textbox.Text.Length];
    bytes = utf8.GetBytes(Textbox.Text); contents = utf8.GetString(bytes,0,Textbox.Text.Length); MessageBox.Show(contents); Clipboard.SetText(contents);


    GetString kann ich nur mit GetString(Byte[],int,int) aufrufen laut SDK, rufe ich es mit GetString(Byte[]) auf, erhalte ich eine Fehlermeldung. Der Inhalt der Messegabox ist übrigens wie immer sauber und man sieht den Datenmüll nicht.




    • Bearbeitet Manfred P Sonntag, 22. Februar 2015 13:15
    Sonntag, 22. Februar 2015 13:14
  • Den Code hätte ich etwas anders gemacht:

    			Encoding utf8 = Encoding.UTF8;
    			byte[] bytes = utf8.GetBytes("Hallo Welt");
    			string content = utf8.GetString(bytes);
    			MessageBox.Show(content);
    			Clipboard.SetText(content);

    Bist du dir sicher, dass Textbox.Text nicht leer ist? Du solltest das nochmals kontrollieren, ob der Wert gültig ist.

    Allerdings mus ich zugeben, dass der Fehler schon seltsam ist, ich habe es mal mit meinen Rchner probiert, und da funktioniert Clipboard.SetText auch nicht - aber ich verwende auch Mono. Aber ob es jetzt daran liegt oder an dem Encoding kann ich dir nicht wirklich sagen.


    © 2015 Thomas Roskop

    Germany // Deutschland

    Sonntag, 22. Februar 2015 13:21
  • Ja ich hab Inhalt drin. Diesen seh ich ja auch in der MessageBox. Und nur das will ich auch haben, was ich dort sehe. Im Clipboard hab ich leider mehr. Wenn ich deinen Code verwende, bekomme ich die Meldung "Keine Überladung für die GetString-Methode nimmt 1 Argumente an". Ich versteh nur Bahnhof.

    Verwende ich hingegen

    utf8.GetString(bytes,0,Textbox.Text.Length)

    kommt keine Fehlermeldung aber ich hab eben auch den Blödsinn wieder im Clipboard. Ich hab doch keine Ahnung *heul*...

    Sonntag, 22. Februar 2015 13:28
  • Der Aufruf ist die nicht Möglich, weil es keine passende Methode gibt?

    Lauf MSDN sollte es diese aber geben: GetString(byte[] bytes);

    Und selbst wenn du deine Methode benutzt, müsste es wie folgt heißen:

    utf8.GetString(bytes, 0, bytes.Length);

    Dies kommt daher, dass du ja die gesamte Länge der Bytes zu einen String verwandeln willst. Denn wenn du z.B. in der Textbox ein ungewöhnliches (also Non-ASCII) Zeichen hast, welches mehr als 2 Bytes verbraucht, so z.B. diese hier:  (U+1E9E), so wird es in zwei Bytes transformiert, aber die Textlänge ist immer noch 1, das würde auch erklären, warum dein Text falsch abgeschnitten wird und ungültig ist, so kann nämlich auch der Nullterminator fehlen:

    Beispiel:

    • Text: ""
    • Binärdarstellung: 1E 9E 00 (<- mit Terminator)
    • Du wandelst nur das erste Byte (da die Textlänge genau eins ist) zu einen Zeichen um: Record Secuence RS (ASCII Sonderzeichen) UND Es fehlt der Nullterminator, demzufolge wird der nächste zufällige Null-Wert als Terminator genommen, was zwei Reaktionen hervorrufen kann: i) Alle dazwischenliegenden Zeichen werden mit interpretiert ii) Du gehst über dienen Speicher heraus, es kommt zu einer Speicherschutzverletzung, deine App wird terminiert, Sofort!




    © 2015 Thomas Roskop

    Germany // Deutschland



    Sonntag, 22. Februar 2015 13:56
  • Das würde heißen, am Ende des letzten Chars hängt kein Nullterminator und ich muss diesen anfügen, wenn ich das richtig verstanden habe. Mit utf8.GetString(bytes,0, bytes.Length) hab ich nämlich immernoch den Plunder drin. Kann ich in Visual Studio 2013 Express irgendwie sehen, wie die einzelnen Chars aussehen? Ich hab das Ding nun erst ne Woche und kenn mich NULL damit aus.

    Und wenn dem so ist, das der Nullterminator fehlt, wie füge ich ihne dauber an? Doch kaum mit char = byte[i] + "\0"; oder?

    Sonntag, 22. Februar 2015 14:03
  • Das mit dem Nullterminator an einen byte[] array anzuhängen geht über viele Wege. Bei deinen kleinen Arrays wäre es einfach, das Array zu kopieren und dort das neue Element anzuhängen.

    Beispiel:

    /*
    * Fügt an ein byte[]-Array einen Null-Terminator an.
    */
    byte[] AppendNullTermninator(byte[] predata) {
         const byte nullT = (byte)'\0';
    
         int max = predata.Length;
         byte[] res = new byte[max + 1]; //Neues, um ein Element vergrößertes Array anlegen
    
         /* Dieser Teil hätte auch mit einer For-Schleife gemacht werden können */
         int i = 0; //Zähler
         while (i < max) {
              res[i] = predata[i]; //Stück für Stück kopieren
              i++;
         }
    
         res[max] = nullT;
         return res;
    }
    Und wegen der Benutzung von VS: Du kannst doch, wenn du eine Stelle hat, wo der Stirng zusammengesetzt wird, einen BreakPoint dort erstellen und dir dann in einem der unteren Anzeigefenster, habe gerade den Namen vergessen, den Inhalt der Variablen anschauen.


    © 2015 Thomas Roskop

    Germany // Deutschland


    Sonntag, 22. Februar 2015 15:32
  • Hab alles gefunden und das Problem gelöst. Danke für den Code. Jetzt ist der String so, wie ich ihn haben wollte. Passt!
    Donnerstag, 26. Februar 2015 10:27