PHP: Zeilen einlesen und modifizieren

  • Hi allerseits, Asche auf mein Haupt, ich raff's wieder nicht.


    ich habe eine Datei mit Inhalt:
    14:18 aktuelle_Uhrzeit
    14:19 S 6 Gross Karben 104 P
    14:19 S 1 Offenbach(Main)Ost 102 P
    14:19 DNR 81272 Koenigstein(Taunus) 22 P
    14:19 IC 2391 Salzburg Hbf 101 P
    14:22 S 2 Niedernhausen(Ts) 103 P
    14:22 S 7 Goddelau-Erfelden 2 P
    usw.
    Das Ergebnis soll sein (fast genauso, aber nur fast):
    14:18 aktuelle_Uhrzeit
    14:19 S6 Gross Karben 104 P
    14:19 S1 Offenbach(Main)Ost 102 P
    14:19 DNR81272 Koenigstein(Taunus) 22 P
    14:19 IC2391 Salzburg Hbf 101 P
    14:22 S2 Niedernhausen(Ts) 103 P
    14:22 S7 Goddelau-Erfelden 2 P
    d. h. das zweite und das dritte Element der Zeile soll zusammen,
    das blanc muss raus.
    irgendwie was mit Array, aber wie ?
    Unter DOS ginge es so:
    lmod /S$ /L* [$1] [$2][$3] [$4] [$5] [$6] [$7] [$8] [$9] [$10] [$11]<input.txt >>output.txt
    Und in PHP ?


    2.tes Problem (wenn das erste gelöst wäre):
    Die obige Ergebnisdatei soll mit einer Art Findfunktion geparst werden.
    Unter DOS ginge das so:
    findstr "EC IC IR RE RB Zusatz Gleis Uhrzeit" output.txt>gefiltert.txt
    (ja, richtig DNR und S-Bahnen sollen nicht kommen :-)) )
    Und wie geht sowas in PHP ?


    für Hilfe ein immer dankbarer Teddie

  • Ungetesteter Schnellschuss:


    Code
    $handle = fopen ("/tmp/inputfile.txt", "r");
    while (!feof($handle)) {
    $zeile = fgets($handle, 4096);
    preg_match("/(\d{1,2}):\d{1,2} (.)/",$zeile,$matches);
    $zeit = $matches[0];
    $rest = $matches[1];
    }
    fclose ($handle);


    Das Beispiel sieht zwar kompliziert aus mit dem regulären Ausdruck /(\d{1,2}):\d{1,2} (.)/ dadurch erspart man sich aber blödes String-Geparse und substr Gefummle.

  • Dein Ausdruck ist allerdings fehlerhaft, oder du hast seine Anfrage nicht richtig verstanden.


    Ich empfehle dir die Zeilen mit fgetcsv (http://de.php.net/manual/de/function.fgetcsv.php ) einzulesen (als delimiter einfach ein space), dann kannst du bequem auf die einzelnen Elemente wie in einem Array zugreifen.
    Ich denke die Lösung kannst du dir dann sogar selber schreiben. ;)

  • Stimmt. Mein Fehler. Wie gesagt, ungetestet :D


    Es muss /(\d{1,2}:\d{1,2}) (.*)/ heissen.
    Wenn die Zeit sicher zweistellig ist könnte man wohl auch /(..:..) (.*)/ schreiben.


    Arrays haben den Nachteil dass Du in Element 0 die Zeit hast und in "Rest" eben den Rest - allerdings OHNE die Leerzeichen.
    Um aus dem "Rest" wieder eine vernünftige Zeile zu machen muss man erst mal die Grösse des Arrays bestimmen, eins abziehen, alle Elemente aneinandersetzen und Leerzeichen einbasteln.


    IMHO sehr umständlich wenn man das mit einem RE in einer Zeile machen kann.


    Es ist halt wie in Perl: Es führen mehr als ein Weg zum Ziel.


    Gruss
    Thomas

  • Hallo Ihr zwei beiden, danke erstmal für die Tips,
    habe - neugierig wie ich bin - beides ausprobiert,
    beides triffts ähnlich, aber nicht genau.
    Das Proggi 1
    $handle = fopen ("$bhf\\$dat#6.txt", "r");
    while (!feof($handle)) {
    $zeile = fgets($handle, 4096);
    preg_match("/(\d{1,2}:\d{1,2}) (.*)/",$zeile,$matches);
    $zeit = $matches[1];
    $rest = $matches[2];
    echo $zeit, " ", $rest, "-\n";
    }
    fclose ($handle);
    ist gut, weil es den führenden blanc vernichtet,
    vorher
    -14:18-aktuelle_Uhrzeit
    -14:19-S 6 Gross Karben 104 P
    -14:19-S 1 Offenbach(Main)Ost 102 P
    -14:19-DNR 81272 Koenigstein(Taunus) 22 P
    nachher
    14:18-aktuelle_Uhrzeit -
    14:19-S 6 Gross Karben 104 P -
    14:19-S 1 Offenbach(Main)Ost 102 P -
    14:19-DNR 81272 Koenigstein(Taunus) 22 P -
    (die bindestriche sind in wirklichkeit auch blancs, die sieht man hier sonst nicht richtig)
    es soll aber so sein
    14:18-aktuelle_Uhrzeit-
    14:19-S6 Gross Karben 104 P-
    14:19-S1 Offenbach(Main)Ost 102 P-
    14:19-DNR81272 Koenigstein(Taunus) 22 P-
    das heisst, da muss noch ein blanc raus und die am Ende weg.


    das Proggi 2
    $row = 1;
    $handle = fopen ("$bhf\\$dat#6.txt","r");
    while ($data = fgetcsv ($handle, 1000, " ")) {
    print "-\n";
    $row++;
    echo $data[1], " ", $data[2],$data[3], " ", $data[4], " ", $data[5], " ", $data[6], " ", $data[7];
    }
    fclose ($handle);
    ist von der Idee her nicht schlecht, aber - wie schon erwähnt - etwas umständlicher und es läuft auch länger.


    Ich würde Proggi 1 bevorzugen, nur
    wie setzt man diesen WegTauschheimer richtig ?
    ich glaube, das begreife ich nie *schluchz*.

  • Zitat

    Original geschrieben von Teddie_Neubert ... preg_match("/(\d{1,2}:\d{1,2}) (.*)/",$zeile,$matches);

    Ersetz mal den regExp durch:


    /(\d{1,2}:\d{1,2}) \s(.+)\s(.+)(.*)/


    dann hast du in matches[1] die Zeit, in 2 und 3 die Zugbezeichnung und 4 den Rest.


    Das kannst du dann zusammenbauen, etwa die Art:


    echo $matches[1], " ",$matches[2], $matches[3], "$matches[4], "\n";


    Das Blank am Ende setzt du übrigens selbst, soweit ich das richtig sehe. Ich hoffe mal das der Syntax stimmt, hab eigentlich gar keine Ahnung von PHP :rolleyes:


    Hth The-spY

    I am the lizard king - I can do anything!


  • Hallo,


    ich versteht nicht, warum Du am Ende ein Blank haben willst, aber irgendeinen Grund wird's schon haben.


    <?php
    $daten=file('in.txt');
    $datei=fopen('out.txt','w');
    foreach ($daten as $d)
    {
    $d=preg_replace('/(.*? .*?) (.*)/i','$1$2',rtrim($d))." \r\n";
    $d=preg_replace('/ /i','-',$d); #test
    fwrite($datei,$d);
    }
    fclose($datei);
    ?>

    Die Zeile mit #test macht aus Leerzeichen Minuszeichen für die bessere Kontrolle, muß nach dem Ausprobieren weg.


    ." \r\n"; mußt Du noch anpassen. vor \r so viele Leerzeichen rein, wie Du am Zeilenende haben willst. Und falls es unter Linux laufen soll, fällt \r weg und es bleibt nur ." \n";


    Gruß, Wolfgang

  • Hallo und zuerst mal Danke an alle Tipgeber,
    nach einigem Gefummle tat es dann, Wolfgangs Tip war der entscheidende.


    Next Turn:
    Habe nun - als String - es so: (jede Zeile mit CR/LF)
    14:18 aktuelle_Uhrzeit
    14:19 S6 Gross Karben 104 P
    14:19 S1 Offenbach(Main)Ost 102 P
    14:19 DNR81272 Koenigstein(Taunus) 22 P
    14:19 IC2391 Salzburg Hbf 101 P
    14:22 S2 Niedernhausen(Ts) 103 P
    14:22 S7 Goddelau-Erfelden 2 P


    Problem:
    Das obige soll mit einer Art Findfunktion geparst werden.
    Unter DOS ginge das so:
    findstr "EC IC IR RE RB Zusatz Gleis Uhrzeit" output.txt>gefiltert.txt
    (ja, richtig DNR und S-Bahnen sollen nicht kommen :-)) )
    Und wie geht sowas in PHP ?


    Den $sel="EC IC IR RE RB Zusatz Gleis Uhrzeit" habe ich auch schon in einem Array - mit explode, das habe sogar ich kapiert :-))


    Wenn ich mit den Elementen des Arrays nacheinander parse, dann stimmt die obige Reihenfolge leider nicht mehr.


    Es muss also quasi-gleichzeitig passieren, so ungefähr wie
    beginne vorn, if einer der inhalte von array gefunden in zeile spuck aus, nächste zeile, bis ende.


    Wichtig ist noch, dass das idealstenfalls aus dem vorhanden String herausextrahiert wird und eben nicht über eine Zwischen-Datei.


    Oder wieder ein von mir so "heissgeliebter" Match-Filter, den ich nie begreife.


    Hat bitte noch jemand eine Idee ?
    Gruss Teddie

  • Original geschrieben von Teddie_Neubert


    Hallo,


    > Wolfgangs Tip war der entscheidende.


    na , dann muß ich wohl nochmal ran. ;-)


    > Habe nun - als String - es so: (jede Zeile mit CR/LF)


    ein String für alle, mit CR/LF zwischendrin, oder je Zeile einen String?


    > findstr "EC IC IR RE RB Zusatz Gleis Uhrzeit" output.txt>gefiltert.txt
    > (ja, richtig DNR und S-Bahnen sollen nicht kommen :-)) )
    > Und wie geht sowas in PHP ?


    In einer Schleife alle prüfen, vielleicht gäb's was eleganteres, aber es funktioniert:


    Wenn Du alle Einträöge in einer einzigen Variablen hast, als lange Zeile mit CR/LF zwischendrin, erstmal in ein Array wandeln:


    <?php
    $daten=explode("\r\n",rtrim($daten));



    Und dann das Array Zeile für Zeile durchgehen und jede Bedingung prüfen:


    $ergebnis='';
    foreach($daten as $d)
    {
    $a=split(' ',$d,3);
    $a=$a[1];
    if (preg_match('/aktuelle_/i',$a)) { $ergebnis.=$d."\r\n"; }
    else if (preg_match('/EC/',$a)) { $ergebnis.=$d."\r\n"; }
    else if (preg_match('/IC/',$a)) { $ergebnis.=$d."\r\n"; }
    else if (preg_match('/IR/',$a)) { $ergebnis.=$d."\r\n"; }
    else if (preg_match('/RE/',$a)) { $ergebnis.=$d."\r\n"; }
    else if (preg_match('/RB/',$a)) { $ergebnis.=$d."\r\n"; }
    }
    echo $ergebnis;
    ?>


    Gruß, Wolfgang

  • Zitat

    Original geschrieben von wgot Wenn Du alle Einträöge in einer einzigen Variablen hast - Ja, so ist es - , als lange Zeile mit CR/LF zwischendrin, erstmal in ein Array wandeln:


    Hallo Wolfgang, ja, das ist es wohl, darauf kam ich leider nicht, danke !


    Zitat

    ...
    if (preg_match('/aktuelle_/i',$a)) { $ergebnis.=$d."\r\n"; }
    else if (preg_match('/EC/',$a)) { $ergebnis.=$d."\r\n"; }
    ...


    Der Lösungsansatz ist prima, und nun kommt die Gemeinheit:
    Die Selektionskriterien sind leider nicht statisch, d. h. der aufrufende User gibt diese in einer von ihm gewählten Reihenfolge und in beliebiger Länge beim Aufruf mit.
    Wir haben dann wohl - wie oben schon beschrieben - ein Array mit Selektionskriterien, welches mit dem neu gebildeten daten-array verglichen werden muss.


    Ich kapiere nicht, wie man eine therorethisch beliebige Anzahl von Selektionskriterien mit den preg_match-aufrufen so verschachtelt, dass das richtige herauskommt.


    Darf ich nochmal Dein Gehirnschmalz bemühen ?
    Gruss Teddie

Jetzt mitmachen!

Sie haben noch kein Benutzerkonto auf unserer Seite? Registrieren Sie sich kostenlos und nehmen Sie an unserer Community teil!