wordcount mit string
-
krümelkacker schrieb:
SeppJ schrieb:
krümelkackers (nach Korrektur)
Tja,
boost::adaptors::transformed
(Boost 1.53) mag doch tatsächlich keime Lambdas, da sie nicht sowas wie einenresult_type
-typedef haben.Da ist übrigens noch ein anderer Fehler drin. Aber den editierst du einfach raus, dann erzähle ich auch niemandem, was dir da peinliches passiert ist .
edit: Oh, ich sehe, das hattest du ohnehin schon geändert. Dann hat's sich erledigt.
-
SeppJ schrieb:
Bei dir müsste das auch gehen, aber dazu wären wohl tiefgehende Fummeleien in der Locale nötig, die hier im Forum vielleicht ein oder zwei Personen beherrschen.
Das geht zwar (copy/paste von http://en.cppreference.com/w/cpp/locale/ctype_char beherrschen bis auf ein, zwei Personen alle hier im Forum), ist aber nicht mal nötig.
struct mystr {}; std::istream& operator>>(std::istream& in, mystr&) { std::istreambuf_iterator<char> it(in), end; std::find_if(std::find_if(it,end,[](char c){return isspace(c);}), end, [](char c){return !isspace(c);}); return in; } int wordcount_fummler(string satz) { istringstream in(satz); return distance(istream_iterator<mystr>(in), istream_iterator<mystr>()); }
-
Edit: Yikes! Da hat schon jemand auf eine praktisch gleiche Lösung verlinkt!
:duck und weg:
-
Uihh! - ein kleiner Programmier-Contest; da darf mein Beitrag nicht fehlen.
std::inner_product
hat noch keiner:#include <functional> // std::plus<> #include <iostream> #include <numeric> // std::inner_product #include <string> #include <cctype> // std::isalnum, etc. namespace werner { int wordcount( const std::string& satz ) { return std::inner_product( begin(satz), end(satz)-1, begin(satz)+1, !satz.empty() && std::isalnum( satz.front() )? 1: 0, std::plus< int >(), []( char prev, char next )->int { return std::isspace( prev ) && std::isalnum( next )? 1: 0; } ); } } int main() { using namespace std; for( string satz; cout << "\nGeben Sie einen Satz ein: ", getline( cin, satz ) && satz != "x"; ) cout << "Sie haben " << werner::wordcount( satz ) << " Woerter eingegeben" << endl; }
Beispiel:
Geben Sie einen Satz ein: Karl-Heinz treibt's um 12:00 bunt - oder ? Sie haben 6 Woerter eingegeben Geben Sie einen Satz ein: Hallo Welt, Du grausame Welt, hast Tabs und auch Zeilen sowie Steuerzeichen Sie haben 12 Woerter eingegeben
Erkennt "Karl-Heinz" als ein Wort; "-" als kein Wort; leider auch "-oder" als kein Wort ... das würde mehr erfordern, als zwei hinter einander stehende Zeichen zu interpretieren.
Gruß
Werner
-
Phil123 schrieb:
Aufgabe:
Der Funktion wordcount wird ein String als Argument u¨bergeben. ...Derartige Aufgabenstellungen schränken doch bereits die Möglichkeiten der Lösung ein. Wieso eigentlich String? Irgendwie muss der Satz doch auch in den Rechner kommen, also per Input - in C++ auch als
std::istream
bekannt: zunächst mal dasmain()
#include <iostream> #include <locale> // std::ctype<> struct WordCounter { WordCounter( int& cnt ) : cnt_( cnt ) {} friend std::istream& operator>>( std::istream& in, WordCounter wc ); private: int& cnt_; }; int main() { using namespace std; for( int words; cout << "\nGeben Sie einen Satz ein: ", cin >> WordCounter( words ); ) cout << "Sie haben " << words << " Wort(e) eingegeben" << endl; }
fehlt noch die Implementierung des Manipulators
WordCounter
:std::istream& operator>>( std::istream& in, WordCounter wc ) { std::istream::sentry ok( in ); if( ok ) { std::ios_base::iostate state = std::ios_base::goodbit; try { enum Mode { Word, Space } mode = Space; wc.cnt_ = 0; typedef std::istream::traits_type Tr; const std::ctype< char >& ct = std::use_facet< std::ctype< char > >( in.getloc() ); for( char c = 0; c != '\n'; ) // bis EOL; irgendwo muss Schluss sein { const Tr::int_type m = in.rdbuf()->sbumpc(); if( Tr::eq_int_type( m, Tr::eof() ) ) // EOF { state |= std::ios_base::eofbit; break; } c = Tr::to_char_type( m ); if( ct.is( std::ctype_base::alnum, c ) ) // Wort { if( mode == Space ) // Wechsel von Space zu Word -> Wortanfang ++wc.cnt_; mode = Word; } else if( ct.is( std::ctype_base::space, c ) ) // Leerzeichen mode = Space; } } catch( ... ) { state |= std::ios_base::badbit; if( in.exceptions() | std::ios_base::badbit ) throw; } in.setstate( state ); } return in; }
ein wenig länglich, dafür werden keine Umwege über einen String genommen (siehe auch hier).
Eine hübsche Aufgabe, und eine nette Übung zur Darstellung von Möglichkeiten zur Programmierung
Gruß
Werner
-
Werner Salomon schrieb:
std::inner_product
hat noch keiner:Ich werfe als Herausforderung std::set_symmetric_difference in den Raum.
-
Ich wag ja kaum, eine Lösung fast ohne Hilfenahme der stl zu präsentieren, aber was sagt ihr hierzu?
template<class Forward1, class Forward2> inline Forward1 find_first_notof(Forward1 first1, Forward1 last1, Forward2 first2, Forward2 last2) { for (; first1 != last1; ++first1) { Forward2 mid2; for (mid2 = first2; mid2 != last2; ++mid2) if (*first1 == *mid2) break; if(mid2==last2) return first1; } return first1; } size_t Count(const string& org, const string& separators) { size_t c = 0; string::const_iterator en, be=org.begin(); do { en=find_first_of(be, org.end(),separators.begin(), separators.end()); if(be!=en) ++c; be=find_first_notof(en, org.end(), separators.begin(), separators.end()); } while(be!=org.end()); return c; } int wordcount_fricker(string satz) { return Count(satz," \n\t -;,.:?!:"); // seperators hinzufügen }
-
[quote="SeppJ"]
Werner Salomon schrieb:
Ich werfe als Herausforderung std::set_symmetric_difference in den Raum.
Wozu? Es gibt noch genug einfache Lösungen
std::string tmp = ' '+s+' '; return (std::unique(tmp.begin(), tmp.end(), [](char c, char d){return isspace(c)!=isspace(d);}) - tmp.begin() + 1)/2 << '\n';
-
Euch zuliebe hab ich die count-Lösung mal angepasst:
int wordcount_Ethon(string satz) { return count_if(satz.begin(), satz.end(), [&](char& c) { return &c == satz.c_str() ? !isspace(c) : isalnum(c) && isspace(*(&c - 1)); }); }
-
Ethon schrieb:
Euch zuliebe hab ich die count-Lösung mal angepasst:
Bitte ohne UB.
-
fummler schrieb:
Ethon schrieb:
Euch zuliebe hab ich die count-Lösung mal angepasst:
Bitte ohne UB.
Seit C++11 doch kein UB mehr? Was stört?
Und selbst wenn : Geht doch eh nur ums frickeln.
-
Habe auch noch eine Lösung gemacht:
#include <algorithm> #include <bitset> #include <iostream> #include <string> #include <vector> using namespace std; void split( const string& text, vector<string>& words ) { bitset<255> separator_lookup; separator_lookup.flip(); const char* alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; for(; *alphabet; ++alphabet) { separator_lookup[ *alphabet ] = false; } string::const_iterator start; bool word = false; for(string::const_iterator it=text.begin(); it!=text.end(); ++it) { if( separator_lookup[ *it ] ) { if( word ) { words.push_back( string(start,it) ); word = false; } } else if( !word ) { start = it; word = true; } } if( word ) words.push_back( string(start,text.end()) ); } unsigned wordcount( const string& text ) { vector<string> words; split( text, words ); return words.size(); } int main() { string text = " Hallo Welt, Du grausame Welt , hast Tabs und auch Zeilen sowie Steuerzeichen Sie haben 12 Woerter eingegeben "; cout << wordcount( text ) << '\n'; }
-
std::array<bool, N> statt std::bitset<N> - Stackspeicher muss sowieso nicht gespart werden und durch das Bits nudeln geht der Performance-Vorteil flöten.
-
Ethon schrieb:
std::array<bool, N> statt std::bitset<N> - Stackspeicher muss sowieso nicht gespart werden und durch das Bits nudeln geht der Performance-Vorteil flöten.
:p
Wenns nun auch um Performance geht... Man hätte natürlich auch einen einfachen Zähler statt std::vector nehmen können. Aber irgendwann kommt wer, und will neben der Anzahl auch noch die einzelnen Wörter haben.:p
-
Ethon schrieb:
std::array<bool, N> statt std::bitset<N> - Stackspeicher muss sowieso nicht gespart werden und durch das Bits nudeln geht der Performance-Vorteil flöten.
Habs gerade mal getestet. Du hast Recht. std::array<bool,N> ist sogar deutlich schneller.
#include <algorithm> #include <bitset> #include <iostream> #include <string> #include <vector> #include <array> #include <cstdlib> #include <boost/timer.hpp> using namespace std; unsigned wordcount_bitset( const string& text ) { bitset<255> separator_lookup; separator_lookup.flip(); const char* alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; for(; *alphabet; ++alphabet) { separator_lookup[ *alphabet ] = false; } string::const_iterator start; bool word = false; unsigned counter = 0; for(string::const_iterator it=text.begin(); it!=text.end(); ++it) { if( separator_lookup[ *it ] ) { if( word ) { ++counter; word = false; } } else if( !word ) { start = it; word = true; } } if( word ) ++counter; return counter; } unsigned wordcount_std_array( const string& text ) { std::array<bool,255> separator_lookup; separator_lookup.fill(true); const char* alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; for(; *alphabet; ++alphabet) { separator_lookup[ *alphabet ] = false; } string::const_iterator start; bool word = false; unsigned counter = 0; for(string::const_iterator it=text.begin(); it!=text.end(); ++it) { if( separator_lookup[ *it ] ) { if( word ) { ++counter; word = false; } } else if( !word ) { start = it; word = true; } } if( word ) ++counter; return counter; } int main() { srand( time(NULL) ); const unsigned SIZE = 1000000000; // 1 Mrd. string text( SIZE, 'x' ); for(unsigned i=0; i!=SIZE/100; ++i) { if( i%100 ) text[i] = ' '; } boost::timer timer; // wordcount_bitset timer.restart(); unsigned words = wordcount_bitset( text ); cout << "wordcount_bitset: " << timer.elapsed() << "s | Words: " << words << '\n'; // 6,9 Sekunden // wordcount_std_array timer.restart(); words = wordcount_std_array( text ); cout << "wordcount_std_array: " << timer.elapsed() << "s | Words: " << words << '\n'; // 1,4 Sekunden }
-
Huch, das srand hat da drin natürlich nichts mehr verloren.
-
Hab das Ganze eben noch mit vector<bool> und vector<char> getestet:
std::vector<bool>: 2,8 Sekunden
std::vector<char>: 1,4 Sekundenarray<bool,255>
undvector<char>( 255, true )
sind gleich schnell.
-
Und mit
STD_VECTOR_BOOL_NOT_SPECIAL
?
-
Sone schrieb:
Und mit
STD_VECTOR_BOOL_NOT_SPECIAL
?Beides 2,8 Sekunden VS11.
-
Das Proposal zur Entfernung oder Deprecation von
std::vector<bool>
wurde nicht umgesetzt. Der Standard wurde sogar erweitert, umstd::hash
zu spezialisieren.