PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Große txt Datei nach doppelten Wörtern/Zahlen durchsuchen?


Gast
2007-07-12, 01:41:40
Hallo! Ich hab folgendes Problem, ich hab eine sehr große TXT Datei (~300kb - ca.15000 Wörter) in der recht unformatiert zahlen Satzzeichen usw stehen.
die Zahlen sind aber hierbei immer von mindestens einem Leerzeichen getrennt.
Nun muß ich hierdrin nach doppelten Einträgen bzw Zaheln suchen und die doppelt vorhandenen dann ausgeben.

Wie kann ich das am besten bewerkstelligen. Programmiersprache wäre mir egal ob C,C++ oder Java hauptsache es funtzt.

Mein erster Gedanke war die txt Datei in Execl zu importieren und dann über Access mittels einer kleinen Abfrage das ganze zu bewerkstelligen aber wegen der größe der Datei kann ich diese erst garnicht in Excel importieren. :(

Hoffe ihr könnt mir da weiterhelfen

Xmas
2007-07-12, 02:50:25
Groß? Das ist doch wohl eher klein. So etwas sollte sich z.B. mit Python sehr einfach erledigen lassen. Das folgende Beispiel zählt z.B. alle durch Leerzeichen getrennte Wörter in einer Textdatei:
data = file("test.txt").read()
words = data.split(" ")
wordcount = {}
for word in words:
wordcount[word] = wordcount.get(word, 0) + 1

for word, count in wordcount.iteritems():
print word, count

rotalever
2007-07-12, 09:24:34
Groß? Das ist doch wohl eher klein. So etwas sollte sich z.B. mit Python sehr einfach erledigen lassen. Das folgende Beispiel zählt z.B. alle durch Leerzeichen getrennte Wörter in einer Textdatei:

Die Frage war doch nach doppelten Wörtern und nicht nach Anzahl, oder?

Im Prinzip musst du für jedes neu eingelesene Wort feststellen, ob Du es schon einmal gelesen hast. Am einfachsten wäre es, jedes Mal wenn ein neues Wort kommt dies ans Ende einer Liste zu speichern und bei jedem gelesenen Wort die Liste einmal komplett zu durchlaufen. Das ist aber von der Laufzeit nicht ganz optimal.

Man könnte die neuen Wörter aber auch in einem Suchbaum sortieren oder in einer Hash-Tabelle. Vll. hilft da ja der STL-Container "map" bei C++ weiter...

Trap
2007-07-12, 10:10:45
Die Frage war doch nach doppelten Wörtern und nicht nach Anzahl, oder?
"doppelt vorhanden" ist eine Anzahl >=2

Gast
2007-07-12, 10:12:39
Ja ich würde gern das ganze so realisieren (denn von der Theorie her kann ich es mir vorstellen):

Jedes Wort suchen, dieses dann in ein 2D Array speichern. In das 0/0 Feld kommt die gefundene Zahl, in das Feld 0/1 die Anzahl der Funde.

Am ende über Printf einfach nur noch die x/2 Felder ausgeben deren Inhalt >1 ist.

Nur kann ich das nicht wirklich in ein Programm umsetzen :(

ScottManDeath
2007-07-12, 10:55:33
In Pseudo Code

import java.io.*;
import java.lang.*; // optional
import java.util.*;



class MyNode
{

public MyNode left;
public MyNode right;

public Comparable key;
public Object value;


public boolean containsKey(Comparable key)
{
int comp = key.compareTo( this.key);

if ( comp == 0)
return true;
else if ( (left != null) && ( comp <= -1) )
return left.containsKey(key);
else if( (right != null) && ( comp >= 1) )
return right.containsKey(key);
else
return false;
}

public Object get(Comparable key)
{
int comp = key.compareTo( this.key);

if ( comp == 0)
return value;
else if ( (left != null) && ( comp <= -1) )
return left.get(key);
else if( (right != null) && ( comp >= 1) )
return right.get(key);
else
return null;

}
public void put(Comparable key, Object value)
{
int comp = key.compareTo( this.key);

if ( comp == 0)
this.value = value;
else if ( comp <= -1 )
{

if(left == null)
{
left = new MyNode();
left.key = key;
left.value = value;
}
else
left.put(key,value);
}
else if( comp >= 1 )
{

if(right == null)
{
right = new MyNode();
right.key = key;
right.value = value;
}
else
right.put(key,value);
}


}
public int size()
{
if ((left == null) && (right == null))
return 1;
else if ((left == null))
return right.size() +1;
else if ( (right == null))
return left.size() +1;
else
return left.size() + right.size() +1;
}

public void to_array(ArrayList arr)
{

if ( left != null)
left.to_array(arr);

arr.add(key);

if( right != null)
right.to_array(arr);
}


}

class MyMap
{
public boolean containsKey(Comparable key)
{
if ( root != null)
return root.containsKey(key);
else
return false;
}

public Object get(Comparable key)
{
if ( root != null)
return root.get(key);
else
return null;

}
public void put(Comparable key, Object value)
{
if ( root == null)
{
root = new MyNode();
root.key = key;
root.value = value;
root.left = null;
root.right = null;


}
else
root.put(key,value);

}
public int size()
{
if (root == null)
return 0;
else
return root.size();

}

public void toArray(ArrayList array)
{
ArrayList tmp = new ArrayList();

if ( root != null)
root.to_array(array);
else
array.clear();
}

private MyNode root;
}


public class Main
{
/** Creates a new instance of Main */
public Main()
{
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) throws IOException
{

String infile="D:\\Development\\Projects\\java\\exc\\infile.txt";
String outfile="D:\\Development\\Projects\\java\\exc\\outfile.txt";

System.out.println("Word count");
System.out.print("Input file: ");System.out.println(infile);
System.out.print("Output file: ");System.out.println(outfile);

BufferedReader f_in ;
BufferedWriter f_out ;

f_in = new BufferedReader(new FileReader(infile));
f_out = new BufferedWriter(new FileWriter(outfile));

String cur_line;
MyMap count_map = new MyMap();

while ( (cur_line = f_in.readLine()) != null)
{
cur_line=cur_line.toLowerCase();

StringTokenizer st = new StringTokenizer(cur_line," \n\r\f,.;:)(!?");
while (st.hasMoreTokens())
{
String cur_token = new String();

cur_token = st.nextToken();

if ( count_map.containsKey(cur_token) )
{
Integer cur_count = (Integer)count_map.get(cur_token) ;
count_map.put(cur_token,new Integer(cur_count.intValue()+1));
}
else
{
count_map.put(cur_token,new Integer(1));
}
}
}

int count_size = count_map.size();

ArrayList count_names = new ArrayList();
count_map.toArray(count_names);

for(int i=0; i < count_size; ++i)
{
f_out.write((String)count_names.get(i));
f_out.write("\t\t\t");
f_out.write( ( (Integer)count_map.get((String)count_names.get(i)) ).toString() );
f_out.newLine();
}
f_out.flush();

System.out.println("program done");
}
}


Das aind meine Lieblingszeilen =):

Integer cur_count = (Integer)count_map.get(cur_token) ;
count_map.put(cur_token,new Integer(cur_count.intValue()+1));


In Pseudo C++

#include <algorithm>
#include <cstdio>
#include <map>
#include <cstdlib>
#include <string>
using namespace std;

int main (int, char**)
{
string infile="D:\\Development\\Projects\\java\\exb_c\\infile.txt";
string outfile="D:\\Development\\Projects\\java\\exb_c\\outfile.txt";

FILE* f_in;
FILE* f_out;

map<string,int> c_map;

if ( f_in = fopen(infile.c_str(),"rt"))
{
char buff [1024];
while ( fgets(buff,1024,f_in))
{
char seps[] = " ,\t\n;.,()!?";
char *token;
token = strtok( strlwr(buff), seps );
while( token != NULL )
{
c_map[token]++;
token = strtok( NULL, seps );
}
}
fclose (f_in);

if(f_out = fopen(outfile.c_str(),"wt"))
{
map<string,int> :: iterator it;
for(it= c_map.begin(); it != c_map.end(); it++)
fprintf(f_out,"%s\t\t\t%i\n", (*it).first.c_str(),(*it).second);
fclose(f_out);
}
}
return 0;
}

Monger
2007-07-12, 10:56:32
In Java fällt mir zu dem Thema sofort das Set ein. Die Suche darin ist rasend schnell. Wenn der passende String noch nicht da ist, füg ihn ins Set ein, wenn nicht, steck ihn in eine List.
Der aufwändigere Teil wird das einlesen und zerschnippeln des Textes, aber falls nötig, unterstützt "String.split()" auch reguläre Ausdrücke. Sollte also insgesamt nicht so das Problem sein.

Edit, @ScottManDeath: darf ich fragen, warum du dir den Stress gibst, eine eigene Map zu implementieren ?!?

AlSvartr
2007-07-12, 11:00:39
<edit>Toll..war ich mal wieder zu langsam :S ... ich sollte die Tabs in umgekehrter Reihenfolge abarbeiten ;D

Öhm, vielleicht steh ich aufm Schlauch, aber bietet sich nicht einfach ein eindimensionales int-Array an, bei dem du die ASCII-Werte (oder entsprechendes) als Index nimmst? Alternativ eben die erwähnte Hashtable, ebenfalls auf diese Weise verwendet, falls das Array sonst zu groß würde.

ScottManDeath
2007-07-12, 11:08:42
In Java fällt mir zu dem Thema sofort das Set ein. Die Suche darin ist rasend schnell. Wenn der passende String noch nicht da ist, füg ihn ins Set ein, wenn nicht, steck ihn in eine List.
Der aufwändigere Teil wird das einlesen und zerschnippeln des Textes, aber falls nötig, unterstützt "String.split()" auch reguläre Ausdrücke. Sollte also insgesamt nicht so das Problem sein.

Edit, @ScottManDeath: darf ich fragen, warum du dir den Stress gibst, eine eigene Map zu implementieren ?!?



Mhmm, k.a. das ist Jahre her. Entweder wollte ich 1337 Poser spielen oder es war Teil der Aufgabe =)

Monger
2007-07-12, 11:17:36
Jetzt ohne es getestet zu haben, aber so sähe mein Ansatz in Java aus:


public class WordCounter {

/**
* @param args
*/
public static void main(String[] args) {
BufferedReader reader;
Set<String> knownWords = new HashSet<String>();
List<String> doubleWords = new ArrayList<String>();

try {
reader = new BufferedReader(new FileReader(args[0]));


String currentLine;
while((currentLine = reader.readLine()) != null){
String[] words = currentLine.split(", ");

for(String word : words){
if(knownWords.contains(word)){
doubleWords.add(word);
}
else{
knownWords.add(word);
}
}
}

} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e){

}
}

}

Das geht selbstverständlich noch schöner, und macht auch noch nicht ganz was die Aufgabe verlangt, aber die Idee sollte klar sein.

Gast
2007-07-12, 11:31:13
Hallo! Schonmal danke für eure Hilfe, momentan versuche ich einfach erstmal die Datei komplett ein und auszulesen aber das scheitert schon, ich bekomme die nicht komplett eingelesen. Wir reden hier immerhin von einer mehr als 300kilobyte große txt-Datei...

Siehe: http://www.kram-hochladen.de/download.php?id=OTE4OTk=
Passwort: 3dcenter

Mit folgendem Einlese/AusgabeCode (C++ mit DevC++) komme ich nur bis zu der Stelle "40025570023034" bzw kurz danach, siehe:

http://img339.imageshack.us/img339/916/problemwy6.jpg (http://imageshack.us)


#include <iostream> // wegen cout cin
#include <fstream> // wegen Dateistreamobjekt
#include <string> // wegen Datentyp string

using namespace std;

int main(int argc, char *argv)
{
ifstream file;
string fileName = "KAEAN.DAT";
int i=0;

file.open(fileName.c_str()); // oeffen im Text-Modus
if(file)
{
string text; // Haupttext
while(!file.eof())
{
char buffer; // Buffer
file.get(buffer);
text += buffer; // Zeichen zusammensetzen
}
cout << text; // fertigen Text ausgeben
file.close();
}
else
{
cout << "Datei Fehler!";
}
cin.get();
return 0;
}

Xmas
2007-07-12, 14:50:15
300 Kilobyte waren vielleicht vor 20 Jahren viel. Du musst die Datei im Binärmodus öffnen, weil sie keine reine Textdatei ist. Und wieso liest du die Datei byteweise ein?

"The right tool for the right job" scheint wirklich kaum jemandem ein Begriff zu sein. Mir käme es erst gar nicht in den Sinn sowas mit Java oder gar C++ zu schreiben.

Python:
data = file(r"c:\KAEAN.DAT", "rb").read()
words = data.split(" ")
wordcount = {}
for word in words:
wordcount[word] = wordcount.get(word, 0) + 1
for word, count in wordcount.iteritems():
if count > 1 and word.isdigit():
print word, count

HajottV
2007-07-12, 15:02:33
Hoi,

sowas macht man nicht mit C/C++/Java, dafür gibt's Perl/AWK/Grep/etc.

cat KAEAN.DAT | tr " " "\12" | grep -E "^[0-9]+$" | sort | uniq -c | grep " 2 " | sed "s/.* //"

Hier (www.merp.de/out.txt) ist das Ergebnis.

Gruß

Jörg

Gnafoo
2007-07-12, 15:44:48
Auch wenn ihr recht habt, wollte ich meine C++-Kenntnisse mal wieder aufbereiten (boah so umständlich hatte ich das gar nicht mehr in Erinnerung). Das ist dabei rausgekommen:


#include <iostream>
#include <string>
#include <fstream>
#include <map>

std::string read_file(std::string filename)
{
std::string contents;
std::ifstream file(filename.c_str(), std::ifstream::in);

if (!file.is_open())
{
std::cerr << "The file couldn't be opened." << std::endl;
return contents;
}

try
{
while (!file.eof())
{
char buffer[512];
file.read(buffer, 512);

contents.append(buffer, file.gcount());
}
}
catch(...)
{
file.close();
throw;
}
file.close();

return contents;
}

int main(int argc, char* argv[])
{
std::string contents = read_file("E:\\Projekte\\csharp\\TestApp2\\debug\\test.txt");
std::map<std::string, int> dictionary;

while (contents.length() > 0)
{
size_t index = contents.find(' ');

if (index == std::string::npos)
index = contents.length() - 1;

std::string word = contents.substr(0, index);
contents = contents.substr(index + 1);

// Laut Google Grobsuche automatisch auf 0 initialisiert.
dictionary[word]++;
}

for (std::map<std::string, int>::iterator it = dictionary.begin(); it != dictionary.end(); it++)
{
std::cout << (*it).first << " " << (*it).second << std::endl;
}

return 0;
}