Wörter aus Text auslesen und Zählen



  • Also meine Aufgabe ist es, eine Text Datei auszulesen, die Wörter dann nach bestimmten Charakteren zu splitten und im Anschluss die dadurch erhaltenen Wörter
    zu zählen. Bei meiner Suche im Netz habe ich viele Beispiele gefunden und konnte mich schon ein bischen daran orientieren, da mir aber manche Kenntnisse noch garnicht zur
    Verfügung stehen dürfen, muss ich in mancherlei Hinsicht leider ungefähr so arbeiten, wie in meinem folgendem Programm code. Allerdings können auch Dinge komsich und doppelt auftreten, da ich als
    Anfänger noch etwas ohne Durchblick bin:

    [ccp]
    //Zu ermittlen ist die jeweilige Anzahl aller Woerter in der ausgelesenen Datei

    class Dateiausgabe
    {
    public static void Main()
    {
    //Oeffnen der entsprechenden Datei
    StreamReader rd = new StreamReader("d:\\heinemann\\Kurzgeschichte.txt");
    string line;
    string zeile;
    string[]words;

    //Aufsplittung nach den betreffenden Satzzeichen, um aus einem Textstring Wortstrings zu fertigen
    while ((line = rd.ReadLine()) != null)
    {
    words=zeile.Split(' ', ',', '.', '?', '!', ':', ';' );
    }

    Dictionary<string, int> zaehler;

    //Ueberpruefung, ob das naechste Wort in dem Text bereits einen gleichen Vorgaenger hat ---> Zaehlererhoehung
    if (words.ContainsKey(words))
    {
    zaehler++;
    }

    //Ausgabe der Anzahl der Woerter
    for (int i = 0; i < words.Length; i++)
    {
    Console.WriteLine(words[i]);
    Console.WriteLine(" {0}", zaehler);
    }

    Console.ReadLine();
    rd.Close();
    }
    }
    [/cpp]

    Woran es in erster Linie scheitert ist die contains Abfrage konform zu gestalten, also den key.
    Anderes Problem ist, dass ich den Zaehler als Integer nicht so einfach erhoehen kann.
    Weiß jemand, wie man das Programm nach ungefähr dem Muster ändern kann? Ich weiß, dass es sicherlich einfacherere Methoden gibt, die leider aber nicht zur Option stehen.



  • Also ich habe da sjetzt mal überarbeitet. Jetzt scheitert es auschließlich noich am Überprüfen, ob ein Wort bereits vorhanden ist:

    //Zu ermittlen ist die jeweilige Anzahl aller Woerter in der ausgelesenen Datei
    
    class Dateiausgabe
    {
        public static void Main()
        {
            //Oeffnen der entsprechenden Datei
            StreamReader rd = new StreamReader("d:\\heinemann\\Kurzgeschichte.txt");
            string line;
    
            /*Aufsplittung nach den betreffenden Satzzeichen, um aus einem Textstring Wortstrings zu fertigen.
            Als Array, da jede Zeile einzeln betrachtet werden muss, sonst wird immer nur die erste betrachtet*/
    
            while ((line = rd.ReadLine()) != null)
            {
                string[] words = line.Split(' ', ',', '.', '?', '!', ':', ';');
    
                Dictionary<string, int> zaehler = new Dictionary<string, int>();
                /*
                if (words.ContainsKey(words))
                {
                    zaehler++;
                }*/
    
                //Ausgabe der Anzahl der Woerter
                for (int i = 0; i < words.Length; i++)
                {
                    string wort = words[i];
    
                    Console.WriteLine(wort);
                    //Console.WriteLine(" {0}", zaehler);//
                }
            }
            rd.Close();  
            Console.ReadLine();
        }
    }
    


    • Hast / Kennst du schon die for each Schleife?
      Mit
    foreach(String word in line.Split(' ', ',', '.', '?', '!', ':', ';'))
    

    kannst du dann alle Wörter einzeln durchgehen.

    • In deiner Version wird ein Wort nicht mitgezählt, falls es in der Zeile schon einmal vorkommt. Soweit ich es verstanden habe, möchtest du aber es auf den ganzen Text beziehen.
      Das Problem beim Dictionary ist, dass du es innerhalb der Zeile neu erzeugst und es somit die alten Einträge "vergessen lässt". Zeile 18 sollte also vor Zeile 14. ...
    • Die einzelnen Wörter müssen dann auch in das Dictionary eingefügt werden.
    • Zeile 20 muss schon in die Schleife in Zeile 26 rein. Sonst erhält man die einzelnen Wörter nicht
    • Zeile 20 - 32: Lässt sich umformen zu:
    int zaehlerVariable;
    if (words.TryGetValue(word, out zaehlerVariable)) // TryGetValue gibt true zurück, falls word in words enthalten ist und schreibt gleichzeitig den Wer in zaehlerVariable.
    {
       words[word] = zaehlerVariable + 1; // Wert erhöhen und zurückschreiben
    }
    else
    {
       words.add(word, 1); // Siehe dritte Anmerkung
    }
    

    Für später:

    • StreamReader sollte mit über using(StreamReader reader = new StreamReader("d:\\heinemann\\Kurzgeschichte.txt")) { ... } initialisiert werden. Das ist sauberer und (Fehler-) sicherer.

    Edit: Tippfehler foreach , danke Dravere


  • Administrator

    @Rhombicosidodecahedron,
    foreach wird zusammengeschrieben 🙂

    @beginner_1234,
    Es gibt C# Tags: [cs].

    Grüssli



  • @Dravere: Danke für den Tip, werde ich berücksichtigen.

    @Rhombicosidodecahedron:
    for each kenne ich leider noch nicht. Die anderen Tips habe ich soweit befolgt und auch weitesgehend verstanden.

    Bei der Schleife ist es jetzt so, dass man mir ein Tip gegeben hat, es soll ungefähr so aussehen:

    if(!zaehler.Contains("der"))
    
    zaehler ["der"]=0;
    
    zaehler["der"]=zaehler["der"]+1;
    

    Jetzt ist klar, dass es sich bei dem "der" um das jeweils zu prüfende Wort handelt. Ich weiß nur nicht, wie ich das schrieben soll, da ich hier ja ein Array benutzen muss, da ich nicht nur ein Wort habe.



  • Mein Ansatz sieht so aus. Aber die "der" müssen noch geändert werden und ich weiß nicht wonach?

    if (!zaehler.Contains("der"))
    {
           zaehler["der"] = 0;
    }
    else
    {
           zaehler["der"] = zaehler["der"] + 1;
    }
    


  • OK, jetzt habe ich es erfolgreich geändert, habe wohl nur ein kleinen Fehler gemacht. Aber meine Ausgabe stimmt nicht mehr:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.IO;
    
    //Zu ermittlen ist die jeweilige Anzahl aller Woerter in der ausgelesenen Datei
    
    class Dateiausgabe
    {
        public static void Main()
        {
            //Oeffnen der entsprechenden Datei
            StreamReader rd = new StreamReader("d:\\heinemann\\Kurzgeschichte.txt");
            string line;
    
            /*Aufsplittung nach den betreffenden Satzzeichen, um aus einem Textstring Wortstrings zu fertigen.
            Als Array, da jede Zeile einzeln betrachtet werden muss, sonst wird immer nur die erste betrachtet*/
    
            Dictionary<string, int> zaehler = new Dictionary<string, int>();
    
            while ((line = rd.ReadLine()) != null)
            {
                string[] words = line.Split(' ', ',', '.', '?', '!', ':', ';');  
    
                //Ausgabe der Anzahl der Woerter
                for (int i = 0; i < words.Length; i++)
                {
                    string wort = words[i];
    
                    if (!zaehler.ContainsKey(wort))
                    {
                    zaehler[wort] = 0;
                    }
                    else
                    {
                    zaehler[wort] = zaehler[wort] + 1;
                    }  
                }
                Console.WriteLine(wort[i]);
                Console.WriteLine(" {0}", zaehler);
            }
            rd.Close();  
            Console.ReadLine();
        }
    }
    


  • Deine Variable i, ist nur innerhalb Deiner for-Schleife bekannt. Sollte beim Compilieren angemeckert werden.

    Oli_1977



  • Warum nicht einfach so?

    Lese alle Zeilen
    mit Regex.Matches(text, @"\w+") splitten
    alle "Value" in einer List<string>
    liste kürzen auf doppelte -> myList.Distinct();
    myList.Count == Wortanzahl

    alles in allen dann ein 10 zeiler - wenn überhaupt.



  • @David W: Ich darf leider nur bereits erworbene Kenntnisse verwenden.
    Oli_1977: Ah Danke, da war der Fehler, jetzt funktionierts einwandfrei.



  • Merk gerade das ich die Aufgabenstellung falsch verstand, ich dachte es geht nur darum die Worte zu zählen und doppelte weg zu lassen, aber das war ja nicht gefragt ^^

    @Oli_1977
    Dein letzter Code hat mehrere Probleme:

    1. i ist nur im schleifen scope
    2. zaehler[wort] = 0; wird knallen weil der Eintrag noch nicht vorhanden ist, du musst ihn noch hinzufügen
    3. Wenn es ein Wort nur einmal gibt steht als Value 0, aber 0x stimmt doch nicht, es muss doch 1 sein
    4. +1 kannst du immer sagen, ob es nach ersten add war oder bei allen weiteren (Siehe meine Lösung)
    [5. Verwende lieber using for den stream reader]
    [6. Definiere eine Variable erst kurz vor der verwendung (line)]
    [7. Teile den Code weiter auf, das erhöht die Sauberkeit, ergibt ein besseres Gesamtbild und fördert wie wiederverwendbarkeit. Einfacher zu maintainen ist es dann ebenso]
    (5, 6 und 7 sind nur zwecks Sauberkeit und Übersicht)

    Hier meine Lösung:

    static void Main(string[] args)
    {
    	var text = ReadText("d:\\heinemann\\Kurzgeschichte.txt");
    	var results = CountWords(text);
    	foreach (var result in results)
    		Console.WriteLine("Wort: {0} = {1}x", result.Key, result.Value);
    	Console.ReadLine();
    }
    
    private static string ReadText(string filePath)
    {
    	string text = "";
    	using (var reader = new StreamReader(filePath))
    		text = reader.ReadToEnd();
    	return text;
    }
    
    private static Dictionary<string, int> CountWords(string text)
    {
    	var countedWords = new Dictionary<string, int>();
    
    	var matches = Regex.Matches(text, @"\w+"); // fals Regex nicht erlaubt ist kannst du hier auch dein Split verwenden
    	foreach (Match match in matches)
    	{
    		var word = match.Value;
    		if (!countedWords.ContainsKey(word))
    			countedWords.Add(word, 0);
    		++countedWords[word];
    	}
    
    	return countedWords;
    }
    

Log in to reply