Log zerlegen

Status
Nicht offen für weitere Antworten.

HoodMaxi

Mitglied
hallo..
ich habe eine log datei die so aussieht:
Code:
192.168.4.9 - - [06/Feb/2009:11:23:51 +0100] "POST [url]http://www.meebo.com/mcmd/test[/url] HTTP/1.1" 0 0 TCP_MISS:NONE
192.168.100.40 - - [06/Feb/2009:11:23:57 +0100] "GET [url]http://www.google.de/aclk?[/url] HTTP/1.1" 302 426 TCP_MISS:DIRECT
192.168.15.1 - - [06/Feb/2009:11:23:57 +0100] "GET [url]http://master.dyngate.com/din.aspx?[/url] HTTP/1.1" 200 224 TCP_MISS:DIRECT
192.168.15.1 - - [06/Feb/2009:11:23:57 +0100] "POST [url]http://master.dyngate.com/dout.aspx?[/url] HTTP/1.1" 200 213 TCP_MISS:DIRECT
192.168.4.10 - - [06/Feb/2009:11:23:57 +0100] "POST [url]http://www.meebo.com/mcmd/test[/url] HTTP/1.1" 200 245 TCP_MISS:DIRECT
...usw...

so.. diesen will ich jetzt in die einzel teile zerlegen wie ip, uhrzeit, datum, url....
wie mach ich das am besten?..
wollte zeile für zeile abgehen und mit dem stringtokenizer zerlegen aber habe es nicht gesahafft die trennzeichen zu ändern..
mfg
 
S

SlaterB

Gast
zeige bitte zumindest den Versuch, denn StringTokenizer mit geändertem Trennzeichen ist recht nett
 
S

SlaterB

Gast
klar ist da ein Schema,
bis zum ersten -, bis zum :, bis ] usw.
 

HoodMaxi

Mitglied
ja und wie änder ich das trennzeichen vom StringTokenizer?
wenn ich StringTokenizer("[") ausführe, wir "[" auch ausgegeben,...
 

HoodMaxi

Mitglied
ja und wie änder ich das trennzeichen vom StringTokenizer?
wenn ich StringTokenizer("[") ausführe, wir "[" auch ausgegeben,...

sry..doppelpost war keine absicht -.-
 
S

SlaterB

Gast
bei der nextToken-Methode kannst du jeweils ein neues Trennzeichen angeben:
tok.nextToken(neues delim);
 

HoodMaxi

Mitglied
hmm... klappt auch nicht wirklich..
weil wenn ich z.b die uhrzeit will muss ich vorher delim auf "1" setzten.. so was ist aber etzt wenns 22 uhr ist und nicht 11!?...
 
S

Spacerat

Gast
Das hatten wir an anderer Stelle in anderem Zusammenhang schon mal... Der String-Tokenizer ist nur noch aus Kompatibilitätsgründen in der JRE. Deswegen sollte man "java.util.regex" oder den Stream-Tokenizer verwenden. Mit Regex hab' ich selbst noch nicht gearbeitet. Beim Stream-Tokenizer lassen sich einzelne Zeichen als Tokens definieren. Und wenn die Log-Datei nun als Stream an so einen Stream-Tokenizer übergeben wird, sollte das zerlegen kein Problem mehr sein.

mfg Spacerat
 
S

SlaterB

Gast
> weil wenn ich z.b die uhrzeit will muss ich vorher delim auf "1" setzten.. so was ist aber etzt wenns 22 uhr ist und nicht 11!?...

was soll delim="1" denn bewirken?
um alles vor der Uhrzeit abzutrennen verwende :, für alles danach gehe bis zum ] oder meinetwegen dem +

> Der String-Tokenizer ist nur noch aus Kompatibilitätsgründen in der JRE.

ein solchen Satz kann man abkürzend sagen, aber wenn einem dann keine richtige Begründung einfällt ist das doch kein Selbstzweck,

String.split und RegEx sind wunderbare Werkzeuge, aber sie können einen StringTokenizer nicht überall ersetzen

String ip = tokenizer.nextToken("-");
String date = tokenizer.nextToken(":");
String time = tokenizer.nextToken("]");

sowas ist in der Eleganz einfach nicht nachzubilden

edit: StreamTokenizer kenne ich nicht besonders, wenn der das gleiche macht mit anderem Namen, dann stört dieser Wechsel in der Tat nicht
 
S

Spacerat

Gast
Die eine Begründung die mir dazu einfällt, ist die von Sun, welche (wenn auch nicht wortwörtlich) einen Satz später folgt...
StringTokenizer is a legacy class that is retained for compatibility reasons although its use is discouraged in new code. It is recommended that anyone seeking this functionality use the split method of String or the java.util.regex package instead.

Und da, wo sich der String-Tokenizer nicht dadurch ersetzen lässt (warum auch immer) gibt es halt noch den Stream-Tokenizer. Initialisieren, die Tokens definieren, lesen... sehr elegant.

mfg Spacerat
 

HoodMaxi

Mitglied
SlaterB hat gesagt.:
> weil wenn ich z.b die uhrzeit will muss ich vorher delim auf "1" setzten.. so was ist aber etzt wenns 22 uhr ist und nicht 11!?...

was soll delim="1" denn bewirken?
um alles vor der Uhrzeit abzutrennen verwende :, für alles danach gehe bis zum ] oder meinetwegen dem +

> Der String-Tokenizer ist nur noch aus Kompatibilitätsgründen in der JRE.

ein solchen Satz kann man abkürzend sagen, aber wenn einem dann keine richtige Begründung einfällt ist das doch kein Selbstzweck,

String.split und RegEx sind wunderbare Werkzeuge, aber sie können einen StringTokenizer nicht überall ersetzen

String ip = tokenizer.nextToken("-");
String date = tokenizer.nextToken(":");
String time = tokenizer.nextToken("]");

sowas ist in der Eleganz einfach nicht nachzubilden

edit: StreamTokenizer kenne ich nicht besonders, wenn der das gleiche macht mit anderem Namen, dann stört dieser Wechsel in der Tat nicht

probiers doch mal aus... wirst sehn das es so nicht hinhaut... denn wenn ich delim ":" nimmt er im nächsten token das ":" mit!
 
S

SlaterB

Gast
Spacerat hat gesagt.:
Die eine Begründung die mir dazu einfällt, ist die von Sun, welche (wenn auch nicht wortwörtlich) einen Satz später folgt...
StringTokenizer is a legacy class that is retained for compatibility reasons although its use is discouraged in new code. It is recommended that anyone seeking this functionality use the split method of String or the java.util.regex package instead.
möchtest du immer noch nur leere Sätze wiederholen oder auch inhaltlich auf mein Argument eingehen,
dass RegEx und split was anderes sind
Und da, wo sich der String-Tokenizer nicht dadurch ersetzen lässt (warum auch immer) gibt es halt noch den Stream-Tokenizer. Initialisieren, die Tokens definieren, lesen... sehr elegant.
wie gesagt: StreamTokenizer macht anscheinend quasi das gleiche und kann dann natürlich gerne 1:1 getauscht werden


HoodMaxi hat gesagt.:
probiers doch mal aus... wirst sehn das es so nicht hinhaut... denn wenn ich delim ":" nimmt er im nächsten token das ":" mit!

selbstverständlich mag das so sein, wer sagt was anderes?
natürlich musst du evtl. noch diverse Zeichen vorne und hinten abschneiden, vielleicht bei der neueren Klasse StreamTokenizer nicht oder auch,
da widerspreche ich nicht
 
S

Spacerat

Gast
Tja. Erklären kann ich das so nicht. Ich kann mal son bissl Code zusammendengeln. In Erklärungen bin ich nicht besonders gut. So zum Beispiel auch, wenn es darum geht, wenn ich vorschlage nicht den String-Tokenizer zu verwenden und das mit scheinbar "leeren" Sätzen begründe. Das "leere" an diesem Satz ist wohl, das SlateB den Stream-Tokenizer nicht kennt bzw. noch nicht verwendet hat.

mfg Spacerat
 

HoodMaxi

Mitglied
Spacerat hat gesagt.:
Tja. Erklären kann ich das so nicht. ... In Erklärungen bin ich nicht besonders gut. So zum Beispiel auch, wenn es darum geht, wenn ich vorschlage nicht den String-Tokenizer zu verwenden und das mit scheinbar "leeren" Sätzen begründe. Das "leere" an diesem Satz ist wohl, das SlateB den Stream-Tokenizer nicht kennt bzw. noch nicht verwendet hat.

mfg Spacerat

okay.. nichts verstanden..^^
ei hast du zufällig son code da?
 
S

Spacerat

Gast
jau... hab' ich... jüngst mal zusammen gestellt...
Code:
import java.io.FileReader;
import java.io.IOException;
import java.io.StreamTokenizer;
import java.util.ArrayList;

public class LogFileReader
{
    public static void main(String ... args)
    throws Throwable
    {
        ArrayList<LogEntry> entrys = new ArrayList<LogEntry>();
        FileReader in = new FileReader("log.txt");
        StreamTokenizer st = new StreamTokenizer(in);
        st.eolIsSignificant(true);
        st.ordinaryChars(32, 127);
        int tk;
        String tmp = "";
        LogEntry e = new LogEntry();
        while((tk = st.nextToken()) != StreamTokenizer.TT_EOF) {
            switch(tk) {
            case ' ':
                if(e.ip == null) {
                    st.sval = tmp;
                    parseIP(st, e);
                }
                tmp = "";
                break;
            case '[':
                tmp = "";
                if(e.date == null) {
                    parseDate(st, e);
                }
                break;
            case ':':
                tmp = "";
                if(e.time == null) {
                    parseTime(st, e);
                }
                break;
            case '\"':
                tmp = "";
                if(e.url == null) {
                    parseURL(st, e);
                }
                break;
            case StreamTokenizer.TT_EOL:
                entrys.add(e);
                e = new LogEntry();
                break;
            default:
                tmp += (char) tk;
            }
        }
        in.close();
        Iterator<LogEntry> it = entrys.iterator();
        while(it.hasNext()) System.out.println(it.next());
    }

    private static void parseIP(StreamTokenizer st, LogEntry e)
    {
        try {
            String tmp[] = st.sval.split("\\."); // !!! Der Punkt hat bei RegExp eine gesonderte Bedeutung !!! 
            if(tmp.length == 4) e.ip = st.sval;
        } catch(Exception ex) {
            // nothing
        }
    }

    private static void parseDate(StreamTokenizer st, LogEntry e)
    throws IOException
    {
        int tk = 0;
        StringBuffer tmp = new StringBuffer();
        while((tk = st.nextToken()) != ':') {
            tmp.append((char) tk);
        }
        st.pushBack();
        e.date = tmp.toString();
    }

    private static void parseTime(StreamTokenizer st, LogEntry e)
    throws IOException
    {
        int tk = 0;
        StringBuffer tmp = new StringBuffer();
        while((tk = st.nextToken()) != ' ') {
            tmp.append((char) tk);
        }
        st.pushBack();
        e.time = tmp.toString();
    }

    private static void parseURL(StreamTokenizer st, LogEntry e)
    throws IOException
    {
        int tk = 0;
        StringBuffer tmp = new StringBuffer();
        while((tk = st.nextToken()) != StreamTokenizer.TT_EOL) {
            tmp.append((char) tk);
        }
        st.pushBack();
        e.url = tmp.toString();
    }

    private static class LogEntry
    {
        private String date, ip, time, url;

        public String toString()
        {
            return "IP: " + ip + "; Date: " + date + "; Time: " + time + "; URL: " + url;
        }
    }
}
Alles in allem war das ehrlich gesagt doch schwieriger als erwartet, wegen der Kapselung (Abschneiden) der einzelnen Elemente. Normalerweise reicht es, beim Stream-Tokenizer aber in der Hauptschleife zwischen "TT_NUMBER" und "TT_WORD" zu switchen.

mfg Spacerat
 
S

SlaterB

Gast
uiuiui, das ist ja ein kompliziertes Programm, hätte ich nicht erwartet,
sorry, da kann ich mir echt nicht verkneifen ein kleines Gegenprogramm zu posten ;) ,

dieses switch auf nextToken() ist doch wirklich genau das, was man in modernen Verarbeitungen lieber nicht sieht,
dass eine bestimmte Information wie ': zur Trennung von Date und Time' an zwei unterschiedlichen Stellen im Programm auftaucht, ist sehr ungünstig

ich bin vorerst enttäuscht von StreamTokeniker, will aber weiterhin nicht absprechen dass das vielleicht dennoch genau das kann wie StringTokenizer:
Code:
		ArrayList<LogEntry> entrys = new ArrayList<LogEntry>();
		FileReader in = new FileReader("log.txt");
		BufferedReader r = new BufferedReader(in);
		String line = null;
		while ((line = r.readLine()) != null) {
			StringTokenizer st = new StringTokenizer(line, "", false);
			String ip = st.nextToken(" ");
			st.nextToken("[");
			String date = st.nextToken(":").substring(1);
			String time = st.nextToken(" ").substring(1);
			st.nextToken("\"");
			String url = st.nextToken("\n").substring(1);
			entrys.add(new LogEntry(ip, date, time, url));
		}
		r.close();
		Iterator<LogEntry> it = entrys.iterator();
		while (it.hasNext())
			System.out.println(it.next());

das substring(1) bei nextToken() mit delim-Änderung ist in der Tat nervig,
zumal recht unnötig, diese kleine Positionsänderung wäre mit 1-2 Zeilen im StringTokenizer gemacht,
da sollte man wirklich den Quellcode kopieren und diesen Schritt verbessern ;)
 
S

Spacerat

Gast
SlaterB hat gesagt.:
dass eine bestimmte Information wie ': zur Trennung von Date und Time' an zwei unterschiedlichen Stellen im Programm auftaucht, ist sehr ungünstig
Das ist einer der Umstände weshalb bei mir am Ende auch dieses "OHJE..."-Gebilde rauskam. Ich bin mir aber Sicher, das es auch Einfacher geht, ohne diese ganzen temporären Strings und StringBuffer. Eigentlich sollte es ganz ohne temporäres Gedöns gehen. Da muss ich wohl angesichts deiner überwältigend kurzen Implementation noch mal ran. Naja... 1:0 für dich.
 
S

Spacerat

Gast
So. Hab' das jetzt noch soweit kürzen können. Diese Implementation erstellt während des Lesevorgangs, ausser neue LogEntrys und "st.sval" keinerlei Instanzen irgendwelcher Objekte (Primitivtypen und Internals von "nextToken()" nicht mitgezählt). Es ist aber anzunehmen, das das auch beim String-Tokenizer so geht. Der Vorteil des Stream-Tokenizers ist, dass er direkt am Stream arbeitet, während für den String-Tokenizer immer mindestens eine Instanz des Typs "String" benötigt. Was solls... In der Kürze liegt die Würze... SlaterB hat also gewonnen.
Code:
import java.io.FileReader;
import java.io.StreamTokenizer;
import java.util.ArrayList;
import java.util.Iterator;

public class LogFileReader
{
    public static void main(String ... args)
    throws Throwable
    {
        ArrayList<LogEntry> entrys = new ArrayList<LogEntry>();
        FileReader in = new FileReader("log.txt");
        StreamTokenizer st = new StreamTokenizer(in);
        st.resetSyntax();
        st.eolIsSignificant(true);
        st.wordChars(33, 127);
        st.whitespaceChars(0, 32);
        int cnt = 0;
        char[] tokens = new char[] {' ', '[', ':', ' ', '"', '\n'};
        LogEntry e = new LogEntry();
        while(st.ttype != StreamTokenizer.TT_EOF) {
            st.nextToken();
            switch(st.ttype) {
            case StreamTokenizer.TT_EOL:
                entrys.add(e);
                e = new LogEntry();
                break;
            case StreamTokenizer.TT_WORD:
                switch(cnt) {
                case 0:
                    e.ip = st.sval;
                    break;
                case 2:
                    e.date = st.sval;
                    break;
                case 3:
                    e.time = st.sval;
                    break;
                case 5:
                    e.url = st.sval;
                }
                st.wordChars(tokens[cnt], tokens[cnt]);
                cnt++;
                cnt %= tokens.length;
                st.whitespaceChars(tokens[cnt], tokens[cnt]);
            }
        }
        in.close();
        Iterator<LogEntry> it = entrys.iterator();
        while(it.hasNext()) System.out.println(it.next());
    }

    private static class LogEntry
    {
        private String date, ip, time, url;

        public String toString()
        {
            return "IP: " + ip + "; Date: " + date + "; Time: " + time + "; URL: " + url;
        }
    }
}
 

HoodMaxi

Mitglied
also vielen dank mal an beide..
habe aber dann doch sie lösung von slaterB genommen da es weniger zu ändern war..
bin mir sicher das andere wäre auch gegangen..
es klappt jetzt alles soweit..
hier der code:

Code:
public static ArrayList<CDaten> Importieren(String dateiname){
    ArrayList<CDaten> LogListe = new ArrayList<CDaten>();
    String Zeile = new String("");
    int Tag = 0;
    int Monat = 0;
    int Jahr = 0;
    String Sek = new String("");
    String IP = new String("");
    String URL = new String("");
    try{
        BufferedReader bur = new BufferedReader(
                new InputStreamReader(new FileInputStream(dateiname)));
        StringTokenizer st;

        while ((Zeile=bur.readLine())!=null){
            st = new StringTokenizer(Zeile," ");
            IP = st.nextToken();
            st.nextToken("[");
            Tag = Integer.parseInt(st.nextToken("/").substring(1));
            Monat = 2; st.nextToken("/");
            Jahr = Integer.parseInt(st.nextToken(":").substring(1));
            st.nextToken(":");
            Sek = st.nextToken(" ").substring(1);
            st.nextToken("T ");
            st.nextToken(" ");
            URL = st.nextToken(" ");
            LogListe.add(new CDaten(Tag,Monat,Jahr,Sek,IP,URL));
        }
    }catch (IOException eIO) {
    System.out.println("Folgender Fehler trat auf: " + eIO);
    }
    return LogListe;
}

...also noch mal danke ;)
 
S

SlaterB

Gast
allgemeine Tipps:
Variablen und Methoden klein schreiben!

niemals new String(), das macht nie Sinn,
wenn du die Variablen vorher definieren willst,
schreibe
String ip = "";
oder noch besser
String ip = null;
 

HoodMaxi

Mitglied
SlaterB hat gesagt.:
allgemeine Tipps:
Variablen und Methoden klein schreiben!

niemals new String(), das macht nie Sinn,
wenn du die Variablen vorher definieren willst,
schreibe
String ip = "";
oder noch besser
String ip = null;

naja haben wir so gelernt und hatte bisher damit noch nie probleme..
aber villt werde ich es ja demnächst berücksichtigen^^
 
Status
Nicht offen für weitere Antworten.
Ähnliche Java Themen
  Titel Forum Antworten Datum
Ü Eurobeträge in möglichst wenig Scheine/Münzen zerlegen (2D-Arrays) Allgemeine Java-Themen 27
J Zerlegen einer Zahl Allgemeine Java-Themen 6
Neumi5694 Parser - Zerlegen verschachtelter Funktionen Allgemeine Java-Themen 2
A ALTER TABLE mit Hilfe von RegEx zerlegen, splitten Allgemeine Java-Themen 5
C Datentypen int in bytes zerlegen und wieder zusammen setzen Allgemeine Java-Themen 13
F String in feste Größe zerlegen Allgemeine Java-Themen 11
H String zerlegen Allgemeine Java-Themen 2
S Threads Liste mit Objekten in Teillisten zerlegen und abarbeiten Allgemeine Java-Themen 3
J String zerlegen in einzelne Strings Allgemeine Java-Themen 7
D String zerlegen Allgemeine Java-Themen 12
R JAI - RGB Bild in 3 Einzelbilder zerlegen Allgemeine Java-Themen 4
X String zerlegen mittels regulärem Ausdruck Allgemeine Java-Themen 31
N String in einzelne Zeichen zerlegen Allgemeine Java-Themen 8
K List in Teillisten zerlegen Allgemeine Java-Themen 2
G Strings zerlegen und substrings auslesen Allgemeine Java-Themen 2
K String zerlegen wie? Allgemeine Java-Themen 8
A Wort in seine Buchstaben zerlegen Allgemeine Java-Themen 37
M Link parsen bzw. zerlegen Allgemeine Java-Themen 9
S String analysieren, zerlegen und überarbeiten Allgemeine Java-Themen 4
T Objekte eindeutig zerlegen und wieder zusammen bauen? Allgemeine Java-Themen 6
Luma String in seine Buchstaben zerlegen? Allgemeine Java-Themen 3
B Datenstruktur elegant zerlegen Allgemeine Java-Themen 6
B Strings zerlegen Allgemeine Java-Themen 9
M String zerlegen? Allgemeine Java-Themen 2

Ähnliche Java Themen

Neue Themen


Oben