Zwei Textdateien vergleichen und Gemeinsamkeiten auflisten [Java]

Neue Frage »

Auf diesen Beitrag antworten »
matt99 Zwei Textdateien vergleichen und Gemeinsamkeiten auflisten [Java]

Hallo,

ich möchte mit Java ein Programm schreiben, was zwei Textdateien (w_test.txt als w und p_test.txt als p) einlesen kann, diese vergleicht und die Gemeinsamkeiten anschließend auflistet. In meinem bisherigen Ansatz habe ich beide Textdatei eingelesen und die erste Datei untereinander hinweg ausgegeben (inkl. Zählung aller Wörter und der Laufzeit des Programms).
Wie kriege ich nun einen Vergleich inkl. der entsprechenden Ausgabe hin?
Auch wollte ich es so machen, dass die Wörter alle untereinander hinweg ausgegeben werden. Mein Problem sind aber Textdateien, dessen Inhalt nebeneinander hinweg geschrieben sind. Hier müsste also durch Leerzeichen eine Trennung erfolgen. Beide Fälle müssten damit abgedeckt sein-

code:
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
import java.io.BufferedReader; 
import java.io.File; 
import java.io.FileReader; 
import java.io.IOException; 
import java.util.Date;

 
public class readtester
{
	public static void main(String[] args) throws IOException
	{
		Date startzeit=new Date();

        //Dateipfade übergeben
        String w_dateipfad ="pfad\\w_test.txt"; 
        String pe_dateipfad ="pfad\\p_test.txt"; 
        File w_datei = new File(w_dateipfad); 
        File p_datei = new File(p_dateipfad); 

        BufferedReader bufferedReaderW; 
        BufferedReader bufferedReaderP; 
        bufferedReaderW = new BufferedReader(new FileReader(w_datei)); 
        bufferedReaderP = new BufferedReader(new FileReader(p_datei)); 
        
        String zeilenW;         
        int i = 0;
        while (null != (zeilenW = bufferedReaderW.readLine())) { 
        i++;
        System.out.println(zeilenW); 
                               
          }

        System.out.println("\nDauer: " +(System.currentTimeMillis() - startzeit.getTime()) + " ms" + "\nGesamtanzahl der Wörter aus W: " + i);
        bufferedReaderW.close();
        bufferedReaderP.close();

	}
}
 
Auf diesen Beitrag antworten »
eulerscheZahl

Mir ist noch nicht klar, wie der Vergleich ablaufen soll.

Kann ich davon ausgehen, dass du Zeile x der einen Datei mit Zeile x der anderen vergleichen willst? Oder kann es sein, dass bei einer Datei dazwischen etwas eingefügt wurde?

Geht es nur um gleich/verschieden, oder willst du auch wissen, was verschieden ist?
Zitat:
Mein Problem sind aber Textdateien, dessen Inhalt nebeneinander hinweg geschrieben sind.

verstehe ich nicht, kannst du ein Beispiel geben?

Übrigens, solche Vergleichsprogramme gibt es schon (z.B. meld)
Auf diesen Beitrag antworten »
matt99

Zitat:
Original von eulerscheZahl
Kann ich davon ausgehen, dass du Zeile x der einen Datei mit Zeile x der anderen vergleichen willst? Oder kann es sein, dass bei einer Datei dazwischen etwas eingefügt wurde?
Geht es nur um gleich/verschieden, oder willst du auch wissen, was verschieden ist?

Die Textdateien sind Listen. Diese sehen ungefähr so aus:

Liste P
Dies
ist
eine
Liste

Liste W
Hier
stehen
Wörter
in
der
Liste

Die Anzahl der Wörter in beiden Listen variiert. Nun will ich schauen, welche Wörter in W auch in P vorkommen. In diesem Fall das Wort "Liste". Und dies hätte ich gern auch als Ausgabe. Die Wörter welche in beiden vorkommen und die Anzahl dieser Wörter (in diesem Fall 1).

Zitat:
Original von eulerscheZahl
Zitat:
Mein Problem sind aber Textdateien, dessen Inhalt nebeneinander hinweg geschrieben sind.

verstehe ich nicht, kannst du ein Beispiel geben?

Bisher bin ich gedanklich nur das Szenario durchgegangen, dass alle Liste (welche als Parameter eingeladen werden) untereinander hinweg geschrieben sind, wie das Beispiel. Mein Problem sind nun aber auch Listen, deren Wörter nacheinander hinterlegt sind, oder gar komplett durcheinander. z.B.

Liste P:
Dies ist eine
Liste

Ich müsste also über ein Tokenization die Leerzeichen erkennen und auch diese als "Trenner" beachten. Mit dem derzeitigen Code erkennt er ja nur Zeile für Zeile. Er würde also in diesem Beispiel sagen "Dies ist eine" und "Liste", Anzahl der Wörter: 2.
Auf diesen Beitrag antworten »
eulerscheZahl

Innerhalb der Zeile kannst du mit split (also line.split(' ')) die Zeile in Worte zerlegen.

Zerlege erst die eine Datei, schreibe die Worte in ein HashSet (da ist die Reihenfolge dann auch egal) und prüfe bei der zweiten Datei mit HashSet.contains(), ob das Wort vorkommt.
Oder erst für beide Dateien getrennt HashSets und dann mit retainAll den Schnitt aus beiden bestimmen.
Wenn du die Anzahl auch noch haben willst, kannst du statt HashSet eine HashMap<String, Integer> nehmen.

Schau mal, ob du das hinkriegst. Sonst kann ich dir heute Abend ein paar Zeilen zusammentippen.
 
Auf diesen Beitrag antworten »
matt99

Vielen Dank für den Gedankenanstoss. line.split und HashSet funktionieren prima für diesen Fall. Alles sieht bisher so aus:

code:
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.Date;
import java.util.HashSet;

public class testerfuerforum {
	public static void main(String[] args) throws IOException {
		Date startzeit = new Date();

		// Dateipfade übergeben
		String w_dateipfad = "pfad\\w_test.txt";
		String p_dateipfad = "pfad\\p_test.txt";
		File w_datei = new File(w_dateipfad);
		File p_datei = new File(p_dateipfad);

		BufferedReader bufferedReaderW;
		BufferedReader bufferedReaderP;
		bufferedReaderW = new BufferedReader(new FileReader(w_datei));
		bufferedReaderP = new BufferedReader(new FileReader(p_datei));

		String zeilenW;
		String zeilenP;
		HashSet<String> hashset_Z = new HashSet<String>();
		HashSet<String> hashset_w = new HashSet<String>();
		HashSet<String> hashset_p = new HashSet<String>();

		// W durchgehen, Integer a für Anzahl der Wörter
		int a = 0;
		while (null != (zeilenW = bufferedReaderW.readLine())) {
			// mit String split alle Wörter beim Leerzeichen trennen
			for (String leerzeichen_teiler_W : zeilenW.split(" ")) {
				a++;
				hashset_w.add(leerzeichen_teiler_W);
			}
		}

		// P durchgehen, Integer b für Anzahl der Wörter
		int b = 0;
		while (null != (zeilenP = bufferedReaderP.readLine())) {
			// mit String split alle Wörter beim Leerzeichen trennen
			for (String leerzeichen_teiler_P : zeilenP.split(" ")) {
				b++;
				hashset_p.add(leerzeichen_teiler_P);				
			}
		}
                //HashSet, Wörteranzahl und Zeit ausgeben 
		System.out.println(leerzeichen_teiler_P);
		System.out.println(hashset_w);
		System.out.println(hashset_p);
		System.out.println("\n\nDauer: "
				+ (System.currentTimeMillis() - startzeit.getTime()) + " ms"
				+ "\nGesamtanzahl der Wörter: " + a + " und " + b);
		bufferedReaderW.close();
		bufferedReaderP.close();

	}
}


Ich habe seperat W und P gelesen. Nun hänge ich noch am HashSet.contains(). Im Internet habe ich gelesen, dass dies als boolean funktioniert. Mein Gedanke war daher die komplette Liste W erst als HashSet einzulesen, danach die Liste P. Nach jeder eingelesenen Zeile soll dann über den boolean geschaut werden, ob das aktuelle Wort in P in der gesamten Liste in W vorkommt. Ist dem so, dann bekomme ich ein true zurück und in diesem Fall wird ein neuer HashSet (nennen wir diesen einfach Z) um genau dieses Wort ergänzt.
Soviel zur Theorie. Den folgenden Code-Ausschnitt habe ich daher über dem Kommentar
code:
1:
//HashSet, Wörteranzahl und Zeit ausgeben 
gelegt.

Am Anfang des Codes habe ich
code:
1:
HashSet<String> hashset_Z = new HashSet<String>();

definiert.

code:
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
		// P durchgehen, Integer b für Anzahl der Wörter
		int b = 0;
		while (null != (zeilenP = bufferedReaderP.readLine())) {
			// mit String split alle Wörter beim Leerzeichen trennen
			for (String leerzeichen_teiler_P : zeilenP.split(" ")) {
				b++;
				hashset_p.add(leerzeichen_teiler_P);
				boolean treffer = hashset_p.contains(hashset_w);
				if (treffer) {
					hashset_Z.add(leerzeichen_teiler_P);
				}
			}
		}

(und das mit dem Einrücken müsste ich auch noch einmal üben~)

Wenn ich nun über
code:
1:
System.out.println(hashset_Z);

mein hashset_Z abfrage, ist dies leer. Wird wohl auch daran liegen, dass ich den hashset_z nicht mit leerzeichen_teiler_P ergänzen sollte, sondern mit einem anderen String an einer bestimmten Stelle (?).
Eventuell hast du da auch eine weitere Idee?
Auf diesen Beitrag antworten »
eulerscheZahl

So wäre ich die Sache angegangen:
code:
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.HashSet;

public class Main {

	static HashSet<String> readWords(String filename) throws IOException {
		HashSet<String> words = new HashSet<String>();
		BufferedReader reader = new BufferedReader(new FileReader(filename));
		String line;
		while ((line = reader.readLine()) != null) {
			String[] wordsInLine = line.split(" ");
			for (String word : wordsInLine)
				words.add(word);
		}
		return words;
	}

	public static void main(String[] args) {
		try {
			HashSet<String> list1 = readWords("/home/eulerschezahl/Dokumente/liste1.txt");
			HashSet<String> list2 = readWords("/home/eulerschezahl/Dokumente/liste2.txt");
			list1.retainAll(list2);
			for (String word : list1)
				System.out.println(word);
		} catch (IOException e) {
			System.out.println("Fehler beim Einlesen");
		}
	}
}


Was bei dir schiefläuft:
code:
1:
while (null != (zeilenP = bufferedReaderP.readLine())) {

bufferedReaderP hat bereits bis zum Dateiende gelesen. also kommt nichts mehr, readLine gibt null zurück.

Und hier bringst du die Listen durcheinander:
code:
1:
2:
3:
4:
5:
6:
7:
for (String leerzeichen_teiler_P : zeilenP.split(" ")) {
	hashset_p.add(leerzeichen_teiler_P);
	boolean treffer = hashset_p.contains(hashset_w);
	if (treffer) {
		hashset_Z.add(leerzeichen_teiler_P);
	}
}


Vorschlag:
code:
1:
2:
3:
4:
5:
6:
7:
8:
9:
for (String leerzeichen_teiler_P : hashset_p) { //gehe über dir Einträge in der einen Liste
	//hashset_p enthält diesen Eintrag bereits
	//hashset_p.add(leerzeichen_teiler_P);
	//prüfe, ob Eintrag in der anderen Liste vorhanden
	boolean treffer = hashset_w.contains(leerzeichen_teiler_P);
	if (treffer) {
		hashset_Z.add(leerzeichen_teiler_P);
	}
}
Auf diesen Beitrag antworten »
matt99

Super, dank dem Vorschlag funktioniert alles! Die Schnittstelle zwischen P und W haut damit auch hin. Besten dank für deine Hilfe.
 
Neue Frage »
Antworten »


Verwandte Themen

Die Beliebtesten »
Die Größten »
Die Neuesten »