while i'm a noob



  • Hallo,

    ich habe hier eine Aufgabe, wo ich mit ein paar Begrifflichkeiten nichts anfangen kann.


    Schreiben Sie ein Programm, welches solange Zeichen aus dem Standardeingabestrom entnimmt, wie das Dateiende noch nicht erreicht ist. Wird das Dateiende erreicht, konvertiert das betreffende Stromobjekt nach false. Handelt es sich bei dem gelesenen Zeichen um ein Alphazeichen (Großbuchstaben und Kleinbuchstaben des Alphabets, das heißt ein Zeichen aus der Menge A = { A .. Z, a .. z, }), dann soll es unverändert ausgegeben werden. Andernfalls soll anstelle des gelesenen Zeichens ein Leerzeichen ausgegeben werden. Das ausführbare Programm soll alpha.exe heißen.

    Was ist denn hier mit Dateiende gemeint?
    Wie lege ich denn diese Mengen fest und unterscheide diese?
    Ist mit Stromobjekt die Schleife gemeint?
    Es hat sicher wer nen heißen Tipp

    Danke Lou



  • Der Standard input stream ist "cin".
    Mit Dateiende ist einfach "cin.eof()" gemeint.
    Zeichenweise lesen machst du mittels "cin.get()".

    Wenn du über das Dateiende hinaus liest, du also mehr Zeichen aus dem Stream rausholen willst, als dort tatsächlich vorhanden sind, wird eof true. Allerdings musst du eof bei cin selbst triggern, die Tastenkombination dafür weiß ich nicht auswendig.

    Um zu testen, ob das Zeichen ein Buchstabe ist, gibt es auch eine Funktion, die heißt glaub "isalpha".



  • cool!
    Vielen Dank.

    PS: Weißt du zufällig noch wie ich auf Groß oder Kleinbuchstaben teste?





  • Die Standardeingabe ist meist mit der Tastatur gekoppelt, kann jedoch auch umgestellt werden.
    https://de.wikipedia.org/wiki/Standard-Datenströme

    Über das Dateiende gibt es auch etwas bei Wikipedia: https://de.wikipedia.org/wiki/End_of_File

    @Lou-Cyphr3 sagte in while i'm a noob:

    PS: Weißt du zufällig noch wie ich auf Groß oder Kleinbuchstaben teste?

    Das ist doch gar nicht geforfdert.



  • @out sagte in while i'm a noob:

    [...]
    Um zu testen, ob das Zeichen ein Buchstabe ist, gibt es auch eine Funktion, die heißt glaub "isalpha".

    Wäre noch anzumerken das std::isalpha(function temolate) je nach locale-Einstellung auch äöüß etc. als Alphazeichen durchlässt (Was korrekt ist). In der Aufgabe steht aber: „...Menge A = { A .. Z, a .. z, })...“, also ohne Umlaute. Die locale sollte dann auf "C" gestellt werden wie in dem Beispiel auf cppreference. Das Beispiel unter std::isalpha(function) ist auch interessant, würde aber in de,ch,at beides mal true zurück geben.

    Oder von Hand:

      char c='c';
    [...]
      
      if ( c >= 'a' && c <= 'z') 
        [...]
    

    ...und Grossbuchstaben natürlich...

    @Lou-Cyphr3 Wenn es nicht gerade eine Prüfung ist tu mir den gefallen und compiliere unter linux mit -o alpha.exe und gib es ab 😃



  • @dirkski sagte in while i'm a noob:

    Oder von Hand:

      char c='c';
    [...]
      
      if ( c >= 'a' && c <= 'z') 
        [...]
    

    Strenggenommen ist das nicht korrekt. Es gibt Encodings wo dieser Test nicht das gewünschte Ergebnis liefert. Beispielsweise Shift JIS oder die EBCDIC Familie.

    Macht aber trotzdem fast jeder so, denn mit den meisten Encodings geht es halt doch.



  • @DirkB sagte in while i'm a noob:

    Das ist doch gar nicht geforfdert.

    Man kann doch trotzdem fragen

    @dirkski

    @Lou-Cyphr3 Wenn es nicht gerade eine Prüfung ist tu mir den gefallen und compiliere unter linux mit -o alpha.exe und gib es ab 😃

    Wieso?



  • @Lou-Cyphr3 sagte in while i'm a noob:

    @dirkski
    Wenn es nicht gerade eine Prüfung ist tu mir den gefallen und compiliere unter linux mit -o alpha.exe und gib es ab 😃

    Wieso?

    Weil es auf Windows-Rechner nicht laufen wird (oder? bin mir nicht mehr sicher) aber es trotzdem richtig ist. Hast dich schließlich an die Vorgaben gehalten. Viel zu diskutiern 😁

    @hustbaer

    Strenggenommen ist das nicht korrekt. Es gibt Encodings wo dieser Test nicht das gewünschte Ergebnis liefert. Beispielsweise Shift JIS oder die EBCDIC Familie.

    Ja, ebcdic ist ja schlimm, a-z nicht mal zusammenhängend... und SchiftJIS, kommen da überhaupt a-z vor? Welche Kodierungen sind eigentlich für c++-Quelltext erlaubt? Werde ich wenn ich Zeit habe mal auf cppreference nachschauen...



  • @dirkski Die ASCII Zeichen haben in Shift JIS fast alle die selben Werte wie in ASCII. Also ja, a-z kommen vor und sind auch zusammenhängend. Nur dummerweise ist Shift JIS nicht "self synchronizing". D.h. wenn du die Bytes davor nicht kennst, dann kannst du nicht wissen wofür z.B. 65 (dezimal) steht. Es könnte für 'A' stehen, aber es könnte auch das 2. Byte einer Sequenz sein.

    Im Gegensatz dazu hat UTF-8 die angenehme Eigenschaft, dass alle Bytes <= 127 auch immer für das ASCII Zeichen mit der selben Nummer stehen, da bei multibyte Sequenzen sämtliche Bytes Werte >= 128 haben. Was bei solchen und ähnlichen Aufgaben halt ungemein praktisch ist, da man oft keinerlei UTF-8 Decoding machen muss. Das einzige was bei dieser Aufgabe passieren würde, ist dass bei non-ASCII Zeichen zu viele Leerzeichen ausgegeben würden.

    Wäre die Aufgabe umgekehrt, also dass man alle [A-Za-z] durch Leerzeichen ersetzen soll, dann wäre das Ergebnis mit UTF-8 sogar 100% korrekt.



  • Hmm, schauen wir uns die Aufgabe an...

    @Lou-Cyphr3 sagte in while i'm a noob:

    [...]
    Schreiben Sie ein Programm, welches solange Zeichen aus dem Standardeingabestrom entnimmt, wie das Dateiende noch nicht erreicht ist.

    Gemeint ist du sollst solange vom Standardinputstream cin lesen bis das Dateiende erreicht ist. Einzelne Zeichen liest du mit formatierter Eingabe so: char c; std::cin >> c;, unformatiert z.B. so: char c; std::cin.get(c);. Die Aufgabe gibt imho nicht her ob formatiert oder unformatiert eingelesen werden soll. Würde mich beim Dozenten beschweren. Der Unterschied ist z.B. das Newline-Zeichen, formatiert wird es ignoriert, unformatiert wird es laut der Aufgabenstellung in ein Leerzeichen umgewandelt.

    Wird das Dateiende erreicht, konvertiert das betreffende Stromobjekt nach false.

    Ob das „betreffende Stromobjekt“ (Yellow? RWE? der Inputstream cin...) bei EOF (Dateiende) nach false (bool) konvertiert bin ich mir dagegen nicht so sicher. Zumindest in der Tabelle vonoperator bool (ganz unten) sieht das nicht so aus. Hat da jemand eine Meinung zu? Vielleicht übersehe ich gerade etwas. Na egal, spätestens beim nächsten Leseversuch ist auch das failbit gesetzt und der Konvertierungsoperator bool gibt false zurück wenn er in einem boolschen Kontext aufgerufen wird. Mein ich.

    #include <iostream>
    
    int main()
    {
            char c;
            // while ( std:.cin >> c )     // formatierte Eingabe Newline und Leerzeichen werden ignoriert
            while ( std::cin.get(c) )     // unformatierte Eingabe, Newline wird auch gelesen
            {
    

    In beiden Fällen wird ein Zeichen nach c eingelesen, sofern kein Fehler auftritt. Der Trick ist das der Gesamtausdruck (cin.get(c) oder cin >> c) das Objekt cin zurückgibt das wiederum innerhalb eines boolschen Kontext (if, while etc) durch den operator bool nach bool konvertiert wird. Der bool-Operator gibt bei Fehlerfall false zurück, ansonsten true. Aber ich bin der Meinung das EOF kein Fehler ist, siehe oben.

    Handelt es sich bei dem gelesenen Zeichen um ein Alphazeichen (Großbuchstaben und Kleinbuchstaben des Alphabets, das heißt ein Zeichen aus der Menge A = { A .. Z, a .. z, }), dann soll es unverändert ausgegeben werden. Andernfalls soll anstelle des gelesenen Zeichens ein Leerzeichen ausgegeben werden.

    Wenn c >= 'a' und c <= 'z' oder c >= 'A' und c <='Z' ist (Vorausgesetzt dein Rechner benutzt einen Zeichencode wo die Buchstabenblöcke zusammenhängen und dein Editor auch. Ascii oder Unicode z.B., hallo hustbear) wäre dies eine Möglichkeit:

    [...]
                    std::cout << ( ( c >= 'a' && c <='z' ) || ( c >= 'A' && c <= 'Z' ) ? c : ' ');
    [...]
    

    Falls ihr den ?:-operator noch nicht hattet geht es auch mit if/else:

    [...]
                if ( ( c >= 'a' && c <='z' ) || ( c >= 'A' && c <= 'Z' ) )
                    std::cout << c;
                else
                    std::cout << ' ';
            }
    
            return 0;
    }
    
    

    Das ausführbare Programm soll alpha.exe heißen.

    #> g++ --std=c++17 -pedantic -W -Wall alpha.cpp -o alpha.exe

    Was ist denn hier mit Dateiende gemeint?

    std::cin.eof()

    Wie lege ich denn diese Mengen fest und unterscheide diese?

    siehe oben oder std::isalpha(char c, std::locale)

    Ist mit Stromobjekt die Schleife gemeint?

    Nein, die Standardeingabe std::cin



  • @dirkski Was für Fälle gibt es denn wo eof auf true geht, aber bad und fail beide false bleiben?
    Und nur um Misverständnisse zu vermeiden: das ist ne 100% ernst gemeinte Frage und soll nichts suggerieren, ich weiss das schlicht und ergreifend nicht 🙂



  • @hustbaer sagte in while i'm a noob:

    @dirkski Was für Fälle gibt es denn wo eof auf true geht, aber bad und fail beide false bleiben?
    Also mir fallen nur zwei Möglichkeiten ein, wo beide false sind, aber eof true ist, und zwar, wenn man eine Zahl oder einen String formatiert einliest:

    #include <iostream>
    #include <sstream>
    #include <string>
    using namespace std;
    
    int main()
    {
        {
            // Eine Zahl formatiert einlesen:
            istringstream iss{ "1234" };
            int zahl{};
            iss >> zahl;
            cout << "zahl = " << zahl << endl;
            cout << "eofbit  = " << boolalpha << iss.eof()  << endl;
            cout << "failbit = " << boolalpha << iss.fail() << endl;
            cout << "badbit  = " << boolalpha << iss.bad()  << endl;
        }
        
        {
            // Einen String formatiert einlesen:
            istringstream iss{ "1234" };
            string str{};
            iss >> str;
            cout << "str = " << str << endl;
            cout << "eofbit  = " << boolalpha << iss.eof()  << endl;
            cout << "failbit = " << boolalpha << iss.fail() << endl;
            cout << "badbit  = " << boolalpha << iss.bad()  << endl;
        }
    }
    
    


  • Dieser Beitrag wurde gelöscht!


  • @out
    Ah, OK. Das erklärt dann auch warum operator bool in dem Fall weiter true zurückgibt: weil eine Zahl erfolgreich gelesen wurde, und die Schleife daher noch eine Runde drehen muss.


Anmelden zum Antworten