Bestimmte Buchstaben in den Elemten eines Vektors suchen?
-
Hallo!
Bei dem Versuch ein Programm zu schreiben, mit dem festellen kann, ob ein Wort viele Ascender und/oder Descender hat und das das längste Wort in einem Wörterbuch ohne Ascender und Descender findet und ausgibt.
Dabei wollte ich so vorgehn:
1. Wörter in einen Vektor einlesen (aus Datei oder durch direkte Eingabe)
2. Wörter des Vektors nach den entsprechenden Buchstaben durchsuchen, die Ascender (b, d, f, h, k, l, t) und/oder Descender (g, j, p, q, y) enthalten und diese in einen extriken Vektor schreiben und aus dem alten löschen (damit am Ende in diesem nur noch Wörter ohne Ascender und Descender stehen).
3. Feststellen, welches Wort z.B. mehr als 3 Ascender/Descender hat und in einen neuen Vektor schreiben, um diesen später auszugeben.
4. Das längste Wort aus dem Vektor mit Wörtern ohne Ascender/Descender finden und ausgeben.Ok, jetzt häng ich also schon bei Punkt 2, weil ich nicht weiss, wie ich einen einzelnen Buchstaben finden lassen kann, um danach das ganze Wort in einen neuen Vektor zu schreiben, das diesen Buchstaben enthält.
Folgenden Code hab ich bereits geschrieben, jedoch sucht dieser nur nach einem Wort das "d" heißt, aber nicht nach dem Buchstaben "d" in den Wörtern des Vektors.
Kann mir vielleicht jemand sagen, wie man dieses Problem lösen kann?
string ch_to_find = "d"; vector<string>::iterator result; result = find(words.begin(), words.end(), ch_to_find); if( result == words.end() ) { cout << "Did not find any element matching " << ch_to_find << endl; } else { cout << "Found a matching element: " << *result << endl; }
-
Schreib dir eine eigene Suchfunktion (oder -Functor) und setz' find_if darauf an:
struct char_finder : public std::unary_function<bool,string> { char_finder(const string& data):md(data){} bool operator()(const string& target) { return target.find_first_of(md)!=string::npos; } private: string md; } //... result = find_if(words.begin(),words.end(),char_finder("d")); //...
-
Imrazor schrieb:
1. Wörter in einen Vektor einlesen (aus Datei oder durch direkte Eingabe)
2. Wörter des Vektors nach den entsprechenden Buchstaben durchsuchen, die Ascender (b, d, f, h, k, l, t) und/oder Descender (g, j, p, q, y) enthalten und diese in einen extriken Vektor schreiben und aus dem alten löschen (damit am Ende in diesem nur noch Wörter ohne Ascender und Descender stehen).
3. Feststellen, welches Wort z.B. mehr als 3 Ascender/Descender hat und in einen neuen Vektor schreiben, um diesen später auszugeben.
4. Das längste Wort aus dem Vektor mit Wörtern ohne Ascender/Descender finden und ausgeben.ich empfehle eine andere Aufteilung des Problems
1.) schreibe eine Funktion, die feststellt, ob ein einzelnes (!) Zeichen einen Ascender oder Descender enthält.
#include <algorithm> #include <string> bool isAsDescender( char c ) { const std::string AsDescender = "bdfhkltgjpqy"; return std::find( AsDescender.begin(), AsDescender.end(), c ) != AsDescender.end(); }
2.) schreibe eine Funktion, die feststellt, ob ein einzelnes Wort kein Zeichen mit A/D (Ascender/Descender) enthält oder mindestens z.B. 3 Zeichen mit A/D enthält. Im ersten Fall soll noch geprüft werden, ob das neue Wort länger als das bisher gefundene längste Wort ohne A/D ist. Im zweiten Fall soll das Wort ausgegeben werden.
#include <iostream> std::string laengstesWortOhne; void AsDescenderChecker( const std::string& word ) { const int n = std::count_if( word.begin(), word.end(), isAsDescender ); if( n >= 3 ) std::cout << word << std::endl; else if( n == 0 && word.size() > laengstesWortOhne.size() ) laengstesWortOhne = word; }
3.) Ändere die Funktion in einen Funktor, um die globale Variable 'laengstesWortOhne' lokal zu machen und mache aus dem Ausgabe-Stream ebenfalls einen Parameter um die Ausgabe ggf. umzulenken.
struct AsDescenderChecker { AsDescenderChecker( std::ostream& out ) : m_out( out ) , m_laengstesWortOhne() {} void operator()( const std::string& word ) { const int n = std::count_if( word.begin(), word.end(), isAsDescender ); if( n >= 3 ) m_out << word << std::endl; else if( n == 0 && word.size() > m_laengstesWortOhne.size() ) m_laengstesWortOhne = word; } std::string LaengstesWortOhne() const { return m_laengstesWortOhne; } private: std::ostream& m_out; std::string m_laengstesWortOhne; };
4.) rufe den neuen Funktor für jedes Wort auf, welches aus der Datei 'input.txt' gelesen wird
#include <fstream> #include <iterator> int main() { std::cout << "\nDas längste Wort ohne Ascender/Descender ist: " << std::for_each( std::istream_iterator< std::string >( std::ifstream( "input.txt" ) ), std::istream_iterator< std::string >(), AsDescenderChecker( std::cout ) ).LaengstesWortOhne() << std::endl; return 0; }
.. und zum Schluß noch eine Frage an die C++-Profies: Ist in obigen Ausdruck im main() lt. C++-Standard sichergestellt, dass erst der Algo for_each ausgeführt wird, bevor der Text '\nDas längste Wort ..' ausgegeben wird?
Gruß
Werner
-
Werner Salomon schrieb:
.. und zum Schluß noch eine Frage an die C++-Profies: Ist in obigen Ausdruck im main() lt. C++-Standard sichergestellt, dass erst der Algo for_each ausgeführt wird, bevor der Text '\nDas längste Wort ..' ausgegeben wird?
Ich würde sagen nein. Wenn man das ganze etwas umschreibt ergibt sich:
operator << ( operator << ( operator << ("\nDas längste Wort ohne Ascender/Descender ist: ", cout) , std::for_each( std::istream_iterator< std::string >( std::ifstream( "input.txt" ) ), std::istream_iterator< std::string >(), AsDescenderChecker( std::cout ) ).LaengstesWortOhne()) ) , std::endl )
oder vereinfacht:
operator <<1 ( operator <<2 ( operator <<3 (a, cout) , b ) , c )
Der C++ Standard legt fest, dass alle Parameter einer Funktion ausgewertet sein müssen, bevor die Funktion selbst ausgewertet werden kann. Er legt aber nicht fest, in welcher Reihenfolge die Auswertung der Parameter geschieht.
Wir wissen hier deshalb nur, das:
a, cout vor dem Aufruf von operator<<3 ausgewertet sein müssen und das
operator<<3(a, cout), b vor dem Aufruf von operator<<2 und das
operator<<2, c vor Aufruf von operator<<1 ausgewertet sein müssen.Ein Compiler könnte z.B. zuerst b mit all seinen Seiteneffekten auswerten (und das Ergebnis zwischenspeichern) und dann erst a, cout gefolgt vom Funktionsaufruf von operator<<3.
Da die Auswertung von b aber Seiteneffekte haben kann, die cout (und damit den Parameter von operator<<3) beeinflussen, kann es sein, dass der Text '\nDas längste Wort ..' nicht das erste ist, was im Stream steht.
-
Danke Hume für die schnelle Antwort; nochmal nachgehakt:
HumeSikkins schrieb:
Wir wissen hier deshalb nur, das:
a, cout vor dem Aufruf von operator<<3 ausgewertet sein müssen und das
operator<<3(a, cout), b vor dem Aufruf von operator<<2 und das
operator<<2, c vor Aufruf von operator<<1 ausgewertet sein müssen.Ein Compiler könnte z.B. zuerst b mit all seinen Seiteneffekten auswerten (und das Ergebnis zwischenspeichern) und dann erst a, cout gefolgt vom Funktionsaufruf von operator<<3.
Also 'a' ist der Text und 'b' ist das Resultat von for_each. Wenn jetzt b vor dem Aufruf operator<<2 ausgewertet sein muss, muss doch der Algorithmus schon durchlaufen worden sein, bevor die Ausgabe <<2, ja bevor irgendeine Ausgabe geschieht.
Wenn ich mich nicht irre, sollte dann sichergestellt sein, dass alle Aktionen und damit auch die Ausgaben in for_each geschehen sind, bevor der Text ausgegeben werden kann. Demnach ist das Verhalten sicher (!) so wie gewünscht.
1.) alle Worte mit mindestens drei A/D-Zeichen ausgeben
2.) Text und das längste Wort ohne A/D-Zeichen ausgeben
.. oder nicht?
Gruß Werner
-
Also 'a' ist der Text und 'b' ist das Resultat von for_each. Wenn jetzt b vor dem Aufruf operator<<2 ausgewertet sein muss, muss doch der Algorithmus schon durchlaufen worden sein, bevor die Ausgabe <<2, ja bevor irgendeine Ausgabe geschieht.
Nicht bevor irgendeine Ausgabe geschieht. Nur bevor operator<<2 aufgerufen wird.
operator<<3 und b sind Parameter für operator<<2. Die beiden können in beliebiger Reihenfolge ausgewertet werden, solange die Parameter von operator<<3 vor dem Aufruf von operator<<3 und beide Parameter von operator<<2 vor dem Aufruf von operator<<2 ausgwertet werden.
Eine mögliche Reihenfolge wäre:
b (also Auswertung des for_each) gefolgt von den Parameter von operator<<3, gefolgt von operator<<3, gefolgt von operator<<2.Eine andere hingegen wäre: Parameter von operator<<3, gefolgt von operator<<3 dann erst b und schließlich operator<<2.
-
Vielen Dank für eure schnelle und tolle Hilfe!
Werd das heut Nacht in Angriff nehmen
-
Also, ich hab den Code mal eingegeben und erhalte aber folgende Fehlermeldung:
/home/xxx/ln_a5_11/src/ascdesc.cpp:49: keine passende Funktion für Aufruf von »std::istream_iterator<std::string, char, std::char_traits<char>, ptrdiff_t>::istream_iterator(std::ifstream)
Die angegebene Zeile 49 ist folgende:
istream_iterator<string>(ifstream("input.txt")),
Aus dem Abschnitt:
int main() { cout << "\nDas längste Wort ohne Ascender/Descender ist: " << for_each( istream_iterator<string>(ifstream("input.txt")), istream_iterator<string>(), AsDescenderChecker(cout) ).LaengstesWortOhne() << endl; return 0; }
Alle Headerdateien sind natürlich eingefügt und "using namespace std;" ebenfalls.
Kann es sein, dass die input.txt im falschen Verzeichnis liegt? Wenn ich mich recht entsinne muss die doch im debug Verzeichnis liegen, oder?
(Programmiere unter Linux mit KDevelop 3)
-
Oh - mir ist da tatsächlich ein Fehler unterlaufen. Der istream_iterator
istream_iterator<string>( ifstream("input.txt") );
verlangt eine nicht const reference im Konstruktor und AFAIK darf man dann keine temporären Objekte übergeben. Mein MS-Compiler ignoriert das aber.
Versuch malint main() { ifstream file( "input.txt" ); cout << "\nDas längste Wort ohne Ascender/Descender ist: " << for_each( istream_iterator<string>( file ), istream_iterator<string>(), AsDescenderChecker(cout) ).LaengstesWortOhne() << endl; return 0; }
.. ein M$-geschädigter
Werner
-
.. und dabei habe ich völlig das Ergebnis der Diskussion mit Hume vergessen. Du benötigts auch eine Varibale für das längste Wort, so dass Du in jedem Fall die Ausgabe in der richtigen Reihenfolge erhälst.
int main() { ifstream file( "input.txt" ); const string laengstesWort = for_each( istream_iterator<string>( file ), istream_iterator<string>(), AsDescenderChecker( cout ) ).LaengstesWortOhne(); cout << "\nDas längste Wort ohne Ascender/Descender ist: " << laengstesWort << endl; return 0; }
.. jetzt haben wir's - oder
Gruß
Werner
-
Vielen Dank für deine Hilfe! Jetzt funktioniert es einwandfrei!