Häufigkeit Zeichen aus Datei/String



  • Hallo,

    Würde gerne eine Funktion schreiben die die Häufigkeit von allen Ascii Zeichen aus einer Textdatei oder String bestimmt und das Zeichen das am häuftigsten vorkommt speichert. Z.B. "Hallo wie geht es euch". e kommt vier mal vor. Hab an map gedacht oder geht es auch simpler ?

    lg und danke



  • Bei 8 bit kannste auch nen unsigned arr[256] = {} nehmen.



  • Wie bekomme ich denn das char das am meisten vorgekommen ist danm aus meinem map oder dem array ?



  • std::max_element



  • void increment(int &i) {
        ++i;
    }
    
    int main(int argc, char** argv) {
    
        fstream inputFile("GeheimeBotschaft.txt", ios::in);
        if (!inputFile) {
            cout << "Fehler! Überprüfen sie ihren Pfad\n";
            throw invalid_argument("inputFile nicht gefunden");
        }
    
        ofstream outputFile("Entschlüsselt.txt", ios::out);
    
        map<char, int> test;
        char text;
    
        while (!inputFile.eof()) {
    
            inputFile.get(text);
            increment(test[text]);
        }
    
        for (map<char, int>::const_iterator i = test.begin(); i != test.end(); ++i)
            cout << i->first << ": " << i->second << endl;
    
        return 0;
    }
    

    So sieht mein Code momentan aus, Zählt schon die Anzahl der jeweiligen Zeichen und gibt diese aus.

    „: 65
    �: 8
    ’: 6
    ¥: 2
    ¦: 4
    §: 1
    ¨: 3
    ©: 1
    «: 1
    ­: 1
    ³: 1
    »: 2
    Å: 17
    Æ: 6
    Ç: 8
    È: 19
    É: 63

    Aber ich weiß nicht wie ich mit max_element jetzt an das „ komme. Will quasi jetzt „ in eine neue char variable extrahieren.



  • auto it = std::max_element(test.begin(), test.end());
    

  • Mod

    Du liest übrigens das letzte Zeichen der Datei falsch ein. Ein Stream setzt das eof-Flag, nachdem eine Leseaktion an mangelnden Daten scheitert, nicht davor.

    P.S.: Willst du die Verteilung nicht ohnehin sortiert haben? Deine nächste Frage wäre doch bestimmt, was das zweithäufigste Zeichen ist.



  • A ok danke Sepp & Cooky.

    Was hat es mit "auto it" auf sich, kann mein compieler leider nichts mit anfangen.

    Sepp, naja ich wollte eingentlich das häuftigste Zeichen im Verschlüsselten Text (wahrscheinlich "e" oder wohl eher "leerzeichen"). Danach hätte ich die Differenz zwischen e bzw. "leerzeichen" und dem häuftigsten Zeichen im Text errechnet und hätte so den Schlüssel um den Text du entschlüsseln ( mit caeser verschlüsselt)



  • ...



  • Danke. Man lernt die aus und das ist wohl an mir vorbei gegangen 🙂



  • Mein GCC hat leider noch kein 11



  • Swordfish schrieb:

    Jolle schrieb:

    Was hat es mit "auto it" auf sich, kann mein compieler leider nichts mit anfangen.

    C++11 – Part 1: Automatic Types

    Dann eben

    char ch = max_element(test.begin(), test.end())->first;
    

    Bin eben erst dazu gekommen es auszuprobieren. Bei deinem Code gibt er leider einfach das letzte Zeichen aus nicht das was am meisten in der map vorkam.



  • #include <fstream>
    #include <iostream>
    #include <vector>
    #include <string>
    #include <set>
    
    struct CharCount
    {
    	explicit CharCount(unsigned char c, std::size_t count)
    		: c(c), count(count)
    	{ }
    
    	unsigned char c;
    	std::size_t count;
    };
    
    bool operator < (CharCount const& lhs, CharCount const& rhs)
    {
    	return lhs.count < rhs.count;
    }
    
    std::string getStreamContent(std::ifstream & str)
    {
    	std::string fileContent;
    	std::string tmp;
    
    	while ( std::getline(str, tmp) )
    	{
    		fileContent += tmp + "\n";
    		tmp.clear();
    	}
    
    	return fileContent;
    }
    
    std::set<CharCount> countChars(std::string const& strContent)
    {
    	std::vector<std::size_t> countings(std::numeric_limits<unsigned char>::max(), 0);
    	for(auto c : strContent)
    	{
    		countings[static_cast<std::size_t>(c)]++;
    	}
    
    	std::set<CharCount> frequenzy;
    	for(std::size_t i = 0; i < countings.size(); ++i)
    	{
    		frequenzy.insert(CharCount(static_cast<char>(i), countings[i]));
    	}
    
    	return frequenzy;
    }
    
    int main()
    {
    	std::string filename;
    	std::cout << "Dateiname: ";
    	std::getline(std::cin, filename);
    
    	std::ifstream file(filename.c_str());
    	if ( !file )
    	{
    		std::cerr << "Datei gibt es nicht" << std::endl;
    		return -1;
    	}
    
    	std::string fileContent = getStreamContent(file);
    	auto frequenzy = countChars(fileContent);
    
    	for(auto cc : frequenzy)
    	{
    		std::cout << "\"" << cc.c << "\"" << "(" << static_cast<std::size_t>(cc.c) << ") -> " << cc.count << std::endl;
    	}
    
    	std::cin.get();
    	return 0x0;
    }
    

    wäre eine halbwegs flexible Möglichkeit



  • ...



  • Habe es jetzt hiermit gelöst

    typedef map<char, int> test;

    struct less_value {

    bool operator()(test::value_type const& l, test::value_type const& r) {
    return l.second < r.second; // second ist der Wert eines Map-Elementpaars
    }
    };


  • Mod

    Warum eine Klasse mit operator(), aber ganz ohne Member? Das ist eine Funktion!



  • Ich habe hier mal noch ein abstrakte Lösung:

    #include <algorithm>
    #include <fstream>
    #include <iostream>
    #include <iterator>
    #include <map>
    #include <string>
    #include <utility>
    using namespace std;
    
    struct most_occurrence
    {
    	template <typename T>
    	bool operator()(const T& lhs, const T& rhs)
    	{
    		return lhs.second < rhs.second;
    	}
    };
    
    template<typename Iter>
    typename map<typename iterator_traits<Iter>::value_type,unsigned>
    all_occurrences(Iter begin, Iter end)
    {
    	map<typename iterator_traits<Iter>::value_type,unsigned> count;
    
    	for(Iter it=begin; it!=end; ++it)
    	{
    		++count[*it];
    	}
    	return count;
    }
    
    int main()
    {
    	ifstream file("test.txt");
    
    	const string content( (istreambuf_iterator<char>(file)), (istreambuf_iterator<char>()) );
    
    	const map<char,unsigned> occurrences = all_occurrences( content.begin(), content.end() );
    
    	const pair<char,unsigned> most = *max_element( occurrences.begin(), occurrences.end(), most_occurrence() );
    
    	for(map<char,unsigned>::const_iterator it=occurrences.begin(); it!=occurrences.end(); ++it)
    	{
    		cout << it->first << ": " << it->second << 'x' << '\n';
    	}
    	cout << most.first << " kommt auf haeufigsten vor: " << most.second << 'x' ;
    }
    


  • SeppJ schrieb:

    Warum eine Klasse mit operator(), aber ganz ohne Member?

    Sowas lässt sich viel leichter inlinen.



  • SeppJ schrieb:

    Warum eine Klasse mit operator(), aber ganz ohne Member? Das ist eine Funktion!

    Will max_element nicht einen Functor?


  • Mod

    duh schrieb:

    Sowas lässt sich viel leichter inlinen.

    Nein.

    out schrieb:

    Will max_element nicht einen Functor?

    Nein, max_element will irgendetwas aufrufbares. Irgendetwas, so dass der Code comp(a,b) etwas sinnvolles ergibt.



  • SeppJ schrieb:

    duh schrieb:

    Sowas lässt sich viel leichter inlinen.

    Nein.

    out schrieb:

    Will max_element nicht einen Functor?

    Nein, max_element will irgendetwas aufrufbares. Irgendetwas, so dass der Code comp(a,b) etwas sinnvolles ergibt.

    Wie würde es denn ohne Functor gehen?

    template <typename T>
    	bool most_occurrence(const T& lhs, const T& rhs)
    	{
    		return lhs.second < rhs.second;
    	}
    
    	// Error: Funktions-template "bool most_occurrence(const T &,const T &)" kann nicht als Funktionsargument verwendet werden.
    	const pair<char,unsigned> most = *max_element( occurrences.begin(), occurrences.end(), most_occurrence );
    

Anmelden zum Antworten