WindowsForms US-Ascii umwandeln in Ausgabe mit Umlauten?



  • Hallo,

    sitze an einem kleinen WindowsForms Programm und bisher macht das Programm auch schon schön was es soll (Benutzereingaben auswerten, ein externes Konsolenprogramm mit Parametern aufrufen, warten bis das Konsolenprogramm fertig ist und anschließend eine Datei einlesen, sowie diese umkopieren und drucken).

    Da ich nicht aus der Sparte der C++/Cli Leute komme, ist das alles relatives Neuland für mich, aber durchaus schaffbar mit der richtigen Doku (habe bisher auch gut was geschafft, denk ich).

    Mein Problem ist nun folgendes:
    ---------------------------------------------------
    Ich lese eine Datei ein, die im Zeichensatz US-ASCII (kann leider nicht geändert werden -> Kartenleseprogramm) erstellt ist. Die dezimalen Werte der Zeichen sind wie folgt -> Ä = 142, Ö = 153, Ü = 154, ß = 225.

    Nun stelle ich leider fest, das beim Drucken oder bei einer Bildschirmanzeige die Umlaute nicht dargestellt werden, in der Textdatei ist allerdings ein Zeichen als Kästchen (nicht unterstütztes Zeichen) angegeben.

    Meine Frage:
    --------------------------------------------------
    Wie konvertiere ich den Zeichensatz, oder wie stelle ich es am Besten an, das Umlaute gedruckt und dargestellt werden? Mir fehlt da bisher leider der Ansatz.

    Der relevante (einfach geschriebene) Code:

    // FileOpen Dialog anzeigen
    			  OpenFileDialog ^ openFileDialog1 = gcnew OpenFileDialog();
    
    			  // FileOpen Dialog Optionen festlegen		  
    			  openFileDialog1->Filter = "Textdateien (*.txt)|*.txt";
    			  openFileDialog1->Title = "Auswahl der Adressdatei";
    			  openFileDialog1->InitialDirectory = "adressen";
    
    			  // Show the Dialog.
    			   if ((openFileDialog1->ShowDialog() == System::Windows::Forms::DialogResult::OK)){
    					StreamReader ^ sr = gcnew System::IO::StreamReader(openFileDialog1->FileName);
    					String ^ line;
    					String ^ mstrasse	= "89:";
    					String ^ mplz	= "90:";
    					String ^ mort	= "91:";
    
    					String ^ strasse;
    
    					int counter;
    					counter = 0;
    
    					int go;
    					go = 0;
    
    					while ((line = sr->ReadLine())){
    						if(line->StartsWith(mstrasse)){
    							line = line->Replace(mstrasse,"");
    							line = line->Trim();
    							strasse = line;
    						}
    						if(line->StartsWith(mplz)){
    							line = line->Replace(mplz,"");
    							line = line->Trim();
    							plz = line;
    						}
    						if(line->StartsWith(mort)){
    							line = line->Replace(mort,"");
    							line = line->Trim();
    							ort = line;
    							go = 1;
    						}
    
    						// Verarbeitung
    						if(go == 1){
    
    							this->label5->Text = plz;
    							this->label6->Text = ort;
    							this->label7->Text = "Verarbeite Datensatz " +counter;
    							this->label10->Text = strasse;
    
    							MessageBox::Show(strasse + "\n" + plz + " " + ort,"Ausgelesene Adresse");
    
    							this->printDocument1->DocumentName = "Datensatz_"+strasse+"_"+plz;
    							this->printDocument1->DefaultPageSettings->Landscape = true;
    							this->printDocument1->PrintPage += gcnew System::Drawing::Printing::PrintPageEventHandler( this, &Form1::PrintMyPage );
    
    							this->printDocument1->Print();
    
    							go = 0;
    							counter++;
    						}
    					}
    

    Habe hier im Forum schon gesucht und bei C++ etwas gefunden, was nicht so richtig funktionieren möchte (bzw. wo ich nichts passendes in der Doku gefunden habe).

    Um eine kleine Hilfestellung wär ich dankbar.

    Gruß Andreas



  • Du musst zuerst mal rausfinden, was das für ein Encoding sein soll. ASCII ist es jedenfalls nicht, da dies Zeichen > 127 nicht enthält!

    Einige der wichtigen Codepages sind hier:
    http://www.microsoft.com/globaldev/reference/WinCP.mspx

    Convertieren kannst Du es dann mit einer entsprechenden "Culture"



  • Vielen Dank schonmal für Deine Antwort.

    http://msdn2.microsoft.com/de-de/library/system.text.encoding(VS.80).aspx

    Dadrüber habe ich schonmal folgendes rausbekommen:
    --------------------------------------------------
    Codepage
    20127

    Name
    us-ascii

    Anzeigename
    US-ASCII

    --------------------------------------------------

    Die kurze Anleitung zu dem Konsolenprogramm (spricht einen Kartenleser an), welches ich aufrufe um eine Ausgabe zu erhalten, sagt mir es ist US-ASCII.

    Das Beispiel dort habe ich auch versucht umzusetzen, die Verweise habe ich angepasst z.B.:

    // Create two different encodings.
       Encoding^ ascii = Encoding::ASCII;
       Encoding^ unicode = Encoding::Unicode;
    
       // Convert the string into a Byte->Item[].
       array<Byte>^unicodeBytes = unicode->GetBytes( unicodeString );
    
       // Perform the conversion from one encoding to the other.
       array<Byte>^asciiBytes = Encoding::Convert( unicode, ascii, unicodeBytes );
    
       // Convert the new Byte into[] a char and[] then into a string.
       // This is a slightly different approach to converting to illustrate
       // the use of GetCharCount/GetChars.
       array<Char>^asciiChars = gcnew array<Char>(ascii->GetCharCount( asciiBytes, 0, asciiBytes->Length ));
       ascii->GetChars( asciiBytes, 0, asciiBytes->Length, asciiChars, 0 );
       String^ asciiString = gcnew String( asciiChars );
    

    Umgesetzt wie folgt (keine Fehlermeldung, kein Resultat). Meinen String aus dem Anfangsquellcode habe ich mit übernommen (strasse).

    // Create two different encodings.
    System::Text::Encoding ^ ascii = System::Text::Encoding::ASCII;
    System::Text::Encoding ^ unicode = System::Text::Encoding::Unicode;
    
    // Convert the string into a Byte->Item[].
    array<Byte>^unicodeBytes = unicode->GetBytes( strasse );
    
    // Perform the conversion from one encoding to the other.
    array<Byte>^asciiBytes = System::Text::Encoding::Convert( unicode, ascii, unicodeBytes );
    
    // Convert the new Byte into[] a char and[] then into a string.
    // This is a slightly different approach to converting to illustrate
    // the use of GetCharCount/GetChars.
    array<Char>^asciiChars = gcnew array<Char>(ascii->GetCharCount( asciiBytes, 0, asciiBytes->Length ));
    ascii->GetChars( asciiBytes, 0, asciiBytes->Length, asciiChars, 0 );
    
    String^ strassen = gcnew String( asciiChars );
    

    geht auch ohne Fehler durch, jedoch ist 'strasse' und 'strassen' identisch, es fehlt weiterhin der Umlaut (vermisse oben auch ein 'decode'?).

    Über 'Cultures' lese ich gerade etwas, werde da aber nicht schlau draus.

    Andreas

    P.s.: bei der Doku zum Kartenleser war auch eine DLL bei, mit der man auch auf den Kartenleser zugreifen kann. Syntax zum Aufrufen der Methode (int ReadVKFile(char *datei, int cnr, int_typ, int_zeichen)) wär da, aber bin ich glaub ich im Moment nicht soweit das einbauen zu können. Dort kann man einen Zeichensatz angeben, der die Kartendaten auch MIT Umlauten ausspuckt. Dachte mir nur der Weg über eine Konvertierung wäre leichter für mich umzusetzen, da die Erstellung und das Auslesen von dem Konsolenprogramm erledigt wird (welches ich nicht geschrieben habe).

    Evtl. hab ich auch gerade einen Bufferoverflow und sollte morgen mal draufschauen :-/, komme sonst aus der 'Web'-Ecke mit PHP/MySql etc. und da ist das schon etwas anderes.



  • ASCII => zeichen zwischen 0 und 127!!! Alles andere wird ignoriert oder durch ein "Ersetungszeichen" ersetzt!

    Frag den Ersteller der Datei, welches Encoding die Datei hat!



  • Hallo Jochen und sorry, wenn ich mich etwas komisch anstelle.

    Der Hersteller verweist auf das Manual und dort steht wörtlich:
    ----------------
    US-ASCII:
    Die dezimalen Werte der Zeichen sind: 'Ä'=142, 'Ö'=153, 'Ü'=154, 'ä'=132, 'ö'=148, 'ü'=129. Das Zeichen 'ß' hat den Wert 225.
    ---------------

    Nun habe ich nochmal bei msdn geschaut und folgende 2 Tabellen gefunden (steht auch Ascii drüber?)

    Visual Studio
    ASCII-Zeichencodes

    Die ASCII-Zeichencodediagramme enthalten die dezimalen und hexadezimalen Werte des ASCII-Zeichensatzes (American Standards Committee for Information Interchange). Der erweiterte Zeichensatz enthält den ASCII-Zeichensatz und 128 weitere Zeichen für das Zeichnen von Grafiken und Linien und wird häufig als "IBM-Zeichensatz" bezeichnet.

    Die Zeichen in Windows mit einem höheren Code als 127 hängen von der ausgewählten Schriftart ab.

    Die Diagramme in diesem Abschnitt zeigen den Standardzeichensatz für eine Konsolenanwendung.

    * Diagramm 1 (Codes 0-127)
    * Diagramm 2 (Codes 128-255)

    In diesen beiden Diagrammen (vielmehr im zweiten) stehen genau die Zeichen drin, die von dem Kartenleser laut Manual benutzt werden.

    http://msdn.microsoft.com/library/deu/default.asp?url=/library/deu/vsintro7/html/_pluslang_ascii_character_codes_chart_2.asp

    Im Moment bin ich etwas durcheinander, sind das nun 2 Paar Schuhe?

    Ich danke Dir vielmals für Deine Geduld.

    Andreas



  • Also, dann handelt es sich wohl um die Codepage 850! (iso-8859-1).

    Dann mit "Encoding::GetEncoding(850)" das passende Encoding erzeugen und die Bytes in einen String umwandeln.

    System::Text::Encoding ^e = System::Text::Encoding::GetEncoding(850);
      // 'Ä'=142, 'Ö'=153, 'Ü'=154, 'ä'=132, 'ö'=148, 'ü'=129. Das Zeichen 'ß' hat den Wert 225. 
      array<System::Byte> ^usascii = {142, 153, 154, 132, 148, 129, 255};
      array<System::Char> ^str = e->GetChars(usascii);
      System::String ^s = gcnew System::String(str);
    


  • Hallo Jochen,
    sorry für die späte Reaktion, aber ich war die letzten Tage nicht hier am Platz.

    Habe versucht Deinen Tip mit dem GetEncoding(850) umzusetzen, leider scheitere ich dran 😞 Umlaute werden in der MessageBox nicht dargestellt.

    Hab ich was falsch gemacht? Dein Beispiel 1zu1 übernommen gibt mir Umlaute aus.
    Der Punkt in Deinem Code:

    array<System::Byte> ^usascii = {142, 153, 154, 132, 148, 129, 225};
    

    muss doch übersetz werden mit den Bytes der Quelle (Textdateiinhalt) oder seh ich das falsch?

    Hier mein Code:

    // Encodings festlegen
    System::Text::Encoding ^ quelle = System::Text::Encoding::ASCII;
    System::Text::Encoding ^ ziel = System::Text::Encoding::GetEncoding(850);
    
    // Bytes auslesen aus dem Quellenstring
    array<Byte>^quelleBytes = quelle->GetBytes( strasse );
    
    // Ziel Bytes erstellen und konvertieren von Ziel und Quell Encoding
    array<Byte>^zielBytes = System::Text::Encoding::Convert( quelle, ziel, quelleBytes );
    
    // Bytes in Chars umwandeln
    array<System::Char> ^str = ziel->GetChars( zielBytes );
    
    // String 
    String^ strasseNeu = gcnew String( str );
    
    MessageBox::Show( + strasseNeu + "\n" + strasse,"Ausgelesene Adresse" );
    

    Habe mir auch mal deine Erklärung zu den verschiedenen Codepages (hier im Forum) durchgelesen, ist schon interessant, wie das alles mal zustande gekommen ist.

    Andreas

    edit:
    ----------------------------------

    // Create two different encodings.
    System::Text::Encoding ^ quelle = System::Text::Encoding::ASCII;
    
    System::Text::Encoding ^e = System::Text::Encoding::GetEncoding(850);
    // 'Ä'=142, 'Ö'=153, 'Ü'=154, 'ä'=132, 'ö'=148, 'ü'=129. Das Zeichen 'ß' hat den Wert 225.
    
    array<System::Byte> ^usascii = quelle->GetBytes( strasse );
    array<System::Char> ^str = e->GetChars(usascii);
    //System::String ^s = gcnew System::String(str);
    
    String^ strasseNeu = gcnew String( str );
    

    macht es auch nicht, war mir nur gerade nochmal in den sinn gekommen.



  • Nochmals zum mitschreiben: DU VERWENDEST *KEIN* ASCII!!!!
    Deshlab hat das "ASCII" in Deinem Code nichts zu suchen!!!

    Was ist "strasse"? Wo steht Dein Byte-Array mit der CP850???



  • ok, es hat mit ASCII nichts zu tun, weil es der Zeichensatz 850 ist und CP850 != ASCII, weil ASCII 127 Zeichen hat und CP850 127+127 (in der erweiterten Tabelle).

    soweit geschluckt und verstanden.

    mittlerweilse sieht der scripteil so aus, wie unten zu sehen ist.

    Es wird ein OpenFile Dialog gestartet , die ausgewählte Datei wird eingelesen mit dem StreamReader und dahingehend modifiziert das die erste Chars einer Zeile ersetzt werden mit Leerzeichen.

    wenn die datei zuende eingelesen wurde, wird ein flag gesetzt (ok) und es geht mit der verarbeitung weiter.

    alles läuft, bis auf die umlaute.

    ich schätze deine hilfe sehr und hoffe ich bin kein all zu schwerer fall.
    normal komme ich aus der php sparte und da ist oop auch kein problem, aber ich stelle mich hier etwas dusselig an, glaub ich.

    wenn das ganze eine browser-basierte anwendung wäre (kann mit php ja auch exe aufrufen und ergebnis abfangen, dateien umkopieren etc.), wüsste ich damit umzugehen aber im moment bin ich halt viel am reininterpretieren.

    // Displays an OpenFileDialog so the user can select a Cursor.
    OpenFileDialog ^ openFileDialog1 = gcnew OpenFileDialog();
    
    openFileDialog1->Filter = "Textdateien (*.txt)|*.txt";
    openFileDialog1->Title = "Auswahl der Adressdatei";
    openFileDialog1->InitialDirectory = "adressen";
    
    // Show the Dialog.
    if ((openFileDialog1->ShowDialog() == System::Windows::Forms::DialogResult::OK)){
    StreamReader ^ sr = gcnew System::IO::StreamReader(openFileDialog1->FileName);
    
    String ^ line;
    String ^ mkkasse	= "80:";
    String ^ mvorname	= "85:";
    String ^ mname		= "87:";
    String ^ mgebdatum	= "88:";
    String ^ mstrasse	= "89:";
    
    String ^ mplz = "8B:";
    String ^ mort = "8C:";	
    
    String ^ vorname;
    String ^ name;
    String ^ plz;
    String ^ ort;
    String ^ strasse;
    String ^ gebdatum;
    String ^ kkasse;
    
    int counter;
    counter = 0;
    
    int go;
    go = 0;
    
    while ((line = sr->ReadLine())){
    	if(line->StartsWith(mkkasse)){
    		line = line->Replace(mkkasse,"");
    		line = line->Trim();
    		kkasse = line;
    	}
    	if(line->StartsWith(mvorname)){
    		line = line->Replace(mvorname,"");
    		line = line->Trim();
    		vorname = line;
    	}
    	if(line->StartsWith(mname)){
    		line = line->Replace(mname,"");
    		line = line->Trim();
    		name = line;
    	}
    	if(line->StartsWith(mgebdatum)){
    		line = line->Replace(mgebdatum,"");
    		line = line->Trim();
    		gebdatum = line;
    	}
    	if(line->StartsWith(mstrasse)){
    		line = line->Replace(mstrasse,"");
    		line = line->Trim();
    		strasse = line;
    	}
    	if(line->StartsWith(mplz)){
    		line = line->Replace(mplz,"");
    		line = line->Trim();
    		plz = line;
    	}
    	if(line->StartsWith(mort)){
    		line = line->Replace(mort,"");
    		line = line->Trim();
    		ort = line;
    		go = 1;
    	}
    
    	// Verarbeitung
    	if(go == 1){
    
    // Code
    System::Text::Encoding ^e = System::Text::Encoding::GetEncoding(850);
    // 'Ä'=142, 'Ö'=153, 'Ü'=154, 'ä'=132, 'ö'=148, 'ü'=129. Das Zeichen 'ß' hat den Wert 225.
    
    array<System::Byte> ^usascii = e->GetBytes( strasse );
    array<System::Char> ^str = e->GetChars(usascii);
    //System::String ^s = gcnew System::String(str);
    
    String^ strasseNeu = gcnew String( str );
    
    		this->label3->Text = name;
    		this->label4->Text = vorname;
    		this->label5->Text = plz;
    		this->label6->Text = ort;
    		this->label7->Text = "Verarbeite Datensatz " +counter;
    		this->label8->Text = gebdatum;
    		this->label9->Text = kkasse;
    		this->label10->Text = strasseNeu;
    
    		MessageBox::Show(name + ", " + vorname + "\n" + strasseNeu + "\n" + strasse + "\n" + plz + " " + ort + "\n" + kkasse + "\n" + gebdatum,"Ausgelesene Adresse");
    
    		this->printDocument1->DocumentName = "Datensatz_"+name+"_"+vorname;
    		this->printDocument1->DefaultPageSettings->Landscape = true;
    		this->printDocument1->PrintPage += gcnew System::Drawing::Printing::PrintPageEventHandler( this, &Form1::PrintMyPage );
    
    		this->printDocument1->Print();
    
    		go = 0;
    		counter++;
    	}
    }
    
    //MessageBox::Show("Anzahl:"+counter);
    this->label7->Text = "Es wurden " + counter + " Datensätze gedruckt.";
    this->label7->Visible = true;
    
    sr->Close();
    


  • Mach es bitte so:

    System::Text::Encoding ^e = System::Text::Encoding::GetEncoding(850);
    StreamReader ^ sr = gcnew System::IO::StreamReader(openFileDialog1->FileName, e);
    

    Dann wird die Datei schon richtig eingelesen und Du hast alle Probleme gelöst"



  • Vielen Dank, das war es!

    Ein langer und steiniger Weg, hoffe ich war nicht all zu schwierig?

    hab gleich mal nachgeschaut und gelernt, hab ich damals übersehen und es wohl an der falschen stelle angefasst:

    StreamReader(System.IO.Stream stream, System.Text.Encoding encoding)
    Member von System.IO.StreamReader

    Zusammenfassung:
    Initialisiert eine neue Instanz der System.IO.StreamReader-Klasse für den angegebenen Stream und mit der angegebenen Zeichencodierung.

    Parameter:
    encoding: Die zu verwendende Zeichencodierung.
    stream: Der zu lesende Stream.

    Ausnahmen:
    System.ArgumentNullException: stream oder encoding ist null.
    System.ArgumentException: stream unterstützt keine Lesevorgänge.

    Danke,

    Andreas

    p.s.: kann zu


Anmelden zum Antworten