Mark: C-fopen Umlaute/Sonderzeichen

Hallo,

ich habe ein Programm in ANSI-C geschrieben, habe jetzt aber noch ein Problem mit Sonderzeichen. Hier ein Auszug:

FILE *ptr;

		ptr = fopen("xxx.txt","rb");  
		  
	while((c = fgetc(ptr)) != EOF)  
	{  

		if(c==13)  
			printf("\n");  
		else  
			printf("%c", c);  
	}  

Er gibt bis auf die Sonderzeichen alles richtig aus. Wenn ich printf("%i", c); ausprobiere, werden mir für die Sonderzeichen negative Werte ausgegeben. Wie kann ich das bewerkstelligen, dass mir die richtigen Zeichen ausgegeben werden? Ohne, dass ich mir jetzt für alle Sonderzeichen einzeln die Werte anzeigen lasse und dann per if-Befehl umwandel?

  1. Moin Moin!

    Hallo,

    ich habe ein Programm in ANSI-C geschrieben, habe jetzt aber noch ein Problem mit Sonderzeichen. Hier ein Auszug:

    FILE *ptr;

      	ptr = fopen("xxx.txt","rb");  
    

    Was passiert, wenn  fopen fehlschlägt, weil Dir Rechte fehlen, die Datei nicht existiert, oder gelockt ist?

      while((c = fgetc(ptr)) != EOF)  
      {  
    
      	if(c==13)  
      		printf("\n");  
      	else  
      		printf("%c", c);  
    

    Hier fehlen zwei Paar geschweifte Klammern, auch wenn der Compiler den Code ohne Klammern frißt. Irgendwann beißt Dich die Tippfaulheit.

      }  
    

    Er gibt bis auf die Sonderzeichen alles richtig aus. Wenn ich printf("%i", c); ausprobiere, werden mir für die Sonderzeichen negative Werte ausgegeben.

    Logisch. Die meisten C-Compiler definieren char als signed. (Was auch immer K&R geraucht haben, als sie das ausgebrütet haben ...)

    Wie kann ich das bewerkstelligen, dass mir die richtigen Zeichen ausgegeben werden?

    Definiere "richtig".

    Ohne, dass ich mir jetzt für alle Sonderzeichen einzeln die Werte anzeigen lasse und dann per if-Befehl umwandel?

    Suchst Du switch/case? Suchst Du eine ASCII-Tabelle?

    Alexander

    --
    Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so".
    1. Hallo,

      deine Kritikpunkte zu meinem Code habe ich im richtigen Programm schon umgesetzt.

      Hatte mir das nur schnell rausgeschrieben und dabei halt das "Unwichtige" weggelassen, was zur reinen Beschreibung des Programmablaufs nicht nötig ist.

      Habe jetzt folgendes:

      #include <stdio.h>  
      #include <conio.h>  
        
      int main ()  
      {  
      unsigned char c;  
      FILE *ptr;  
        
        
      ptr = fopen("xxx.txt","rb");  
        
      while((c = fgetc(ptr)) != 255)  
      {  
        
      if(c==13)  
      printf("\n");  
      else  
      printf("%i ", c);  
      }  
      getch();  
      return 0;  
      }
      

      Das Problem ist, dass er mir für "ä" z.B. 228 und "ü" 252 ausgibt, d.h. es werden falsche Zeichen ausgebeben.

      Es kann ja nicht sein, das ich für den kompletten ASCII Code von 128 - 255 switch Anweisungen schreibe?!

      1. Hallo,

        Das Problem ist, dass er mir für "ä" z.B. 228 und "ü" 252 ausgibt

        ... was ja auch völlig korrekt ist. Das sind die richtigen Codes für ä und ü. In den Latin1/ISO-8859-x-Codierungen werden diese Codes direkt 1:1 in die jeweiligen Bytewerte umgesetzt, in UTF-8 werden sie mit den Bytefolgen 0xC3, 0xA4 und 0xC3, 0xBC codiert.

        d.h. es werden falsche Zeichen ausgebeben.

        Nämlich welche?

        Es kann ja nicht sein, das ich für den kompletten ASCII Code von 128 - 255 switch Anweisungen schreibe?!

        Nö, ich wüsste auch nicht warum.
        Wenn allerdings deine Eingabedatei in einer ISO-Codierung vorliegt, die Ausgabe aber im UTF-8-Kontext stattfinden soll, müsstest du alle Zeichen ab 0x80 in ihre 2-Byte-Darstellung umwandeln. Wikipedia zeigt dir, wie's geht.

        So long,
         Martin

        --
        F: Was sagt die kleine Kerze zur großen Kerze?
        A: Ich gehe heute nacht aus!
      2. Moin Moin!

        Hallo,

        deine Kritikpunkte zu meinem Code habe ich im richtigen Programm schon umgesetzt.

        Hatte mir das nur schnell rausgeschrieben und dabei halt das "Unwichtige" weggelassen, was zur reinen Beschreibung des Programmablaufs nicht nötig ist.

        Habe jetzt folgendes:

        /.../

        int main ()
        {
        unsigned char c;
        FILE *ptr;

        ptr = fopen("xxx.txt","rb");

        Nochmal: Was passiert, wernn fopen fehlschlägt?

        while((c = fgetc(ptr)) != 255)

        Die Zuweisung an c ist ok, der Typ von c ist falsch! Was liefert fgetc() zurück? Sieh bitte mal in der Doku nach. Es ist weder ein signed char noch ein unsigned char. Denn beide Varianten könnten nicht den gesamten Wertebereich PLUS eof-Bedingung abdecken.

        Der Vergleich mit 255 ist vollkommen falsch und ein Folgefehler des kaputten impliziten Casts von fgetc(). Du willst mit der Konstante EOF vergleichen, und mit nichts anderem.

        {

        if(c==13)

        Wenn überhaupt, willst Du c hier casten.

        printf("\n");
        else
        printf("%i ", c);
        }
        getch();
        return 0;
        }

        
        >   
        > Das Problem ist, dass er mir für "ä" z.B. 228 und "ü" 252 ausgibt, d.h. es werden falsche Zeichen ausgebeben.  
          
        Was ist an en Zeichen 2, 5 und 8 falsch? Exakt diese Zeichen forderst Du mit printf("%i",c) an. Was willst Du stattdessen ausgeben?  
          
        
        > Es kann ja nicht sein, das ich für den kompletten ASCII Code von 128 - 255 switch Anweisungen schreibe?!  
          
        Was genau willst Du ausgeben?  
          
        Alexander
        
        -- 
        Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so".
        
        1. Wie schon geschrieben, ich habe hier nicht die Schutzmechanismen mit reingeschrieben. Natürlich überprüfe ich mit dem NULLZeiger, ob die Datei existiert.

          Ähm ja, habe c nun als int deklariert ;-)

          Ich möchte ganz gerne, das wenn ich eine Textdatei, die z.B. im ANSI Format gespeichert wird, mir alle Sonderzeichen von 128-255 auf der Konsole richtig ausgebeben werden. Z.B. ä(132 in Ascii) soll nicht als õ(228 ANSI)ausgegegeben werden.

          1. Hello,

            Wie schon geschrieben, ich habe hier nicht die Schutzmechanismen mit reingeschrieben. Natürlich überprüfe ich mit dem NULLZeiger, ob die Datei existiert.

            Ähm ja, habe c nun als int deklariert ;-)

            Ich möchte ganz gerne, das wenn ich eine Textdatei, die z.B. im ANSI Format gespeichert wird, mir alle Sonderzeichen von 128-255 auf der Konsole richtig ausgebeben werden. Z.B. ä(132 in Ascii) soll nicht als õ(228 ANSI)ausgegegeben werden.

            Du willst also CP437 verwenden
            Warum tust Du es dann nicht durchgängig?
            siehe https://forum.selfhtml.org/?t=185669&m=1232540

            Liebe Grüße aus dem Cyberspace

            Tom vom Berg

            --
            Nur selber lernen macht schlau
            http://bergpost.annerschbarrich.de
        2. Hello,

          Das Problem ist, dass er mir für "ä" z.B. 228 und "ü" 252 ausgibt, d.h. es werden falsche Zeichen ausgebeben.

          Das ist ISO-8859-1 http://de.wikipedia.org/wiki/ISO-8859-1

          das bedeutet also, dass Du (oder wer auch sonst) das File in dieser Codierung erstellt hast. Der Editor hat also für eine Anzeige eines ü auf em Bildschirm richtigerweise einen Bytewert #252 ins File geschrieben.

          Du müsstest also erst einmal entscheiden:

          • welche Zeichen du brauchst
          • in welcher Codepage die vorhanden sind
          • wie Du deinen Editor nebst Screen dazu bringen kannst, diese Codepage zu verwenden
          • mit welchem Screen (= Monitor + Grafikkarte) du die Datei wieder ausgeben willst,
              also welche Codepage der benutzt

          Und dann darfst Du fleißig konvertieren.

          Beim guten alten C auf PC war die Codepage 437 sehr beliebt. Die hat mir auch immer am besten gefallen ;-))

          http://de.wikipedia.org/wiki/Codepage_437

          Es kann ja nicht sein, das ich für den kompletten ASCII Code von 128 - 255 switch Anweisungen schreibe?!

          Doch, es kann sein. Allerdings machst Du die Transformationen besser nicht mit Switch-Anweisungen, sondern mit (korrespondierenden) Arrays.

          Liebe Grüße aus dem Cyberspace

          Tom vom Berg

          --
          Nur selber lernen macht schlau
          http://bergpost.annerschbarrich.de
  2. hi,

    [..] Wie kann ich das bewerkstelligen, dass mir die richtigen Zeichen ausgegeben werden? Ohne, dass ich mir jetzt für alle Sonderzeichen einzeln die Werte anzeigen lasse und dann per if-Befehl umwandel?

    Hier gabs die Tage erst einen Thread zur Codepage/DOS-Konsole/Zeichenkodierung, musst mal gucken, viel Glück.

    Hotte

    --
    Content-type: text/self
  3. Hallo,

    Er gibt bis auf die Sonderzeichen alles richtig aus. Wenn ich printf("%i", c); ausprobiere, werden mir für die Sonderzeichen negative Werte ausgegeben. Wie kann ich das bewerkstelligen, dass mir die richtigen Zeichen ausgegeben werden? Ohne, dass ich mir jetzt für alle Sonderzeichen einzeln die Werte anzeigen lasse und dann per if-Befehl umwandel?

    offen gesagt bin ich jetzt nicht sooo ein großer Experte, was Zeichensätze etc. angeht, und ich habe auch weder Lust und Zeit, selber irgendwelche Tests durchzuführen. Sollten meine Ausführungen also Quatsch sein, dann steinigt mich halt. ;-)
    Wie schon die anderen geschrieben haben, liegt das Problem nicht unbedingt in deinem Programm, sondern erstmal an dieser "Windows-Konsole", die den sog. OEM-Zeichensatz verwendet. Ansonsten wird unter Windows ein anderer Zeichensatz benutzt (das, was du als ANSI bezeichnest). Und wie bereits Charles Petzold in seinen Büchern über Windowsprogrammierung dargelegt hat: "Unglücklicherweise macht das Vorhandensein dieser zwei Zeichensätze die Sache nicht doppelt so einfach."
    Um es erstmal ganz einfach zu machen, vergessen wir vorläufig die Textdatei und nehmen folgendes Beispielprogramm:

      
    #include <stdio.h>  
      
    int main()  
    {  
    	printf("äöüßÄÖÜ\n");  
      
    	return 0;  
    }  
    
    

    Du siehst: Auch das wird von der Windows-Konsole als OEM interpretiert.
    Um das richtig umzuwandeln, probier mal die Windows-spezifische CharToOem()-Funktion aus, die sich mit Google leicht finden lässt. Wenn es gut klappt, sag ich mal herzlichen Glückwunsch. Ansonsten meld dich nochmal, dann kann man sich weiter an eine Lösung herantasten.
    Viel Erfolg - ich hoffe, das hat dir geholfen.

    Viele Grüße
    Def