Jan: Bestimmte Zeilen aus CSV anzeigen

Hallo Leute!

Ich hab ein tab-separated CSV und möchte nur bestimmte Zeilen auslesen.
Ich weiss welchen Wert ich auslesen möchte, aber leider steht dieser nicht immer in der gleichen Spalte, und zwar kann er in 20 verschiedenen Spalten vorkommen (Spalten 17 - 36). Ich kann nun bei jedem Zeilen-Durchlauf aus-ifen, ob der Wert irgendwo drinnen steht, bloss ist das etwas umständlich.

Weiss jemand vielleicht, wie es leichter ginge?

lg, Jan

  1. Hi,

    Weiss jemand vielleicht, wie es leichter ginge?

    mit einem DBMS. Das hat nämlich genau diese - notwendigen - Mechanismen bereits implementiert.

    Cheatah

    --
    X-Self-Code: sh:( fo:} ch:~ rl:° br:> n4:& ie:% mo:) va:) de:] zu:) fl:{ ss:) ls:~ js:|
    X-Self-Code-Url: http://emmanuel.dammerer.at/selfcode.html
    X-Will-Answer-Email: No
    X-Please-Search-Archive-First: Absolutely Yes
    1. Hi!

      mit einem DBMS. Das hat nämlich genau diese - notwendigen - Mechanismen bereits implementiert.

      Ich weiss, aber ich bekomme die Daten als CSV aus einem DOS-Programm heraus ;o(

      lg, Jan

      1. Hi,

        Ich weiss, aber ich bekomme die Daten als CSV aus einem DOS-Programm heraus ;o(

        dann konvertierst Du sie entweder, oder Du baust die von Dir beschriebene Mechanik.

        Cheatah

        --
        X-Self-Code: sh:( fo:} ch:~ rl:° br:> n4:& ie:% mo:) va:) de:] zu:) fl:{ ss:) ls:~ js:|
        X-Self-Code-Url: http://emmanuel.dammerer.at/selfcode.html
        X-Will-Answer-Email: No
        X-Please-Search-Archive-First: Absolutely Yes
  2. Hallo Jan,

    Cheatah hat im Prinzip schon recht.

    Es gibt aber auch für CSV so eine einfache Methode.

    $suchstring="|5|";
    <---- Der Wert nachdem du suchst (Mit Seperatoren)
    $fp= fopen ("datei.csv","r");
    <---- Die CSV Datei
    while ($zeile = fgets($fp,4096)){
    <---- Zeilen einzeln einlesen
    if (strstr($zeile,$suchstring)){
    <---- eingelesene Zeile mit Suchstring vergleichen
    $array = explode("|",$zeile);
    <---- Die Zeile mit gefundenen Suchstring aufteilen (hab hier nen anderen Separator genommen.
    print "$array[0]<BR>";}}
    <---- die gewünschte Spalte auslesen

    Mit diesem einfachen Script bekommst du nur die Zeilen ausgelesen die den gewünschten Suchstring enthalten. (Achtung Groß- und Kleinschreibung.

    Ich würd dir auf alle Fälle empfehlen den Suchstring zu ändern.

    Ich hoffe das hilft weiter

    Gruß

    Bobby

  3. Hello,

    Ich hab ein tab-separated CSV und möchte nur bestimmte Zeilen auslesen.
    Ich weiss welchen Wert ich auslesen möchte, aber leider steht dieser nicht immer in der gleichen Spalte, und zwar kann er in 20 verschiedenen Spalten vorkommen (Spalten 17 - 36). Ich kann nun bei jedem Zeilen-Durchlauf aus-ifen, ob der Wert irgendwo drinnen steht, bloss ist das etwas umständlich.

    Wie groß ist denn die Datei, um die es geht? Bis ca. 140.000kByte Dateigröße kann man die Datei gut in ein assoziatives Array einlesen und in ein indiziertes sogar bis zu 200.000kByte. Das kann man dann zielgenau abfragen, wo die Treffer liegen. Dafür gibt es spezielle CSV-Funktionen in PHP.

    Die Begrenzungen entstehen durch die meistens eingestellte Speicherbegrenzung auf 8 oder 10 MByte pro Script. Ein Array "bläst" sich gegenüber einer CSV-Datei ungefähr auf den fünf bis 7-fachen Speicherbedarf auf.

    Alternativ kann man eine CSV-Datei natürlich auf die klassische Art abarbeiten, also Zeile für Zeile, was dannn aber je nach Speicher- und Cachemodell erheblich in die Verarbeitungszeit gehen kann.

    Umständlich ist das ganze bestimmt nicht, wenn man sich die Arrayfunktionen nochmals genau anschaut:

    http://de.php.net/manual/de/function.fgetcsv.php

    Wensentlich dabei ist nur, dass die CSV-Datei "sauber" sein muss, d.h. dass es eben keinen Zeilenendezeichen innerhalb der Datensätze geben darf, bzw. bei der Verwendung von "enclosure" eben keine Kombination "delimiter""enclosure""delimiter" innerhalb eines Satzes.

    Zu den Standardbegriffen:
    PHP             Standard
    "delimiter" --> seperator
    "enclosure" --> delimiter

    In SQL-Datenbanken gibt es oft die Möglichkeit des Exports oder des Imports von "SDF"-Dateien (Standard Data Format). Da spricht man dann manchmal von

    seperated by ... delimited with ...

    Bei MySQL heißt es aber dann z.B.

    fields terminated by ',' enclosed by '"'
       lines terminated by '\r\n'

    Der automatische Import mit

    LOAD DATA INFILE <dateiname>
    INTO <tabellenname>
    FIELDS TERMINATED BY "\t" ENCLOSED BY '"'

    funktioniert aber nur, wenn die Datenformate aufeinander abgestimmt sind. Wenn z.B. bei Zahlenwerten das Komma als Dezimalzeichen benutzt wird, oder Daten in einem ungewöhnlichen Format gechrieben werden, hast Du schon ein Problem.

    Harzliche Grüße aus http://www.annerschbarrich.de

    Tom

    --
    Fortschritt entsteht nur durch die Auseinandersetzung der Kreativen
    Nur selber lernen macht schlau
    1. Hi,

      Bis ca. 140.000kByte Dateigröße kann man die Datei gut in ein assoziatives Array einlesen und in ein indiziertes sogar bis zu 200.000kByte.

      das meinst Du hoffentlich nicht ernst, oder? Selbst wenn Du "Byte" statt "kByte" geschrieben hättest, wären solche Größen jenseits von Gut und Böse.

      Alternativ kann man eine CSV-Datei natürlich auf die klassische Art abarbeiten, also Zeile für Zeile,

      Was genau das ist, was man beim kompletten Einlesen auch tut - mit allen Zeilen, statt nur mit denen, die man braucht, bis das Ergebnis gefunden wurde.

      Cheatah

      --
      X-Self-Code: sh:( fo:} ch:~ rl:° br:> n4:& ie:% mo:) va:) de:] zu:) fl:{ ss:) ls:~ js:|
      X-Self-Code-Url: http://emmanuel.dammerer.at/selfcode.html
      X-Will-Answer-Email: No
      X-Please-Search-Archive-First: Absolutely Yes
      1. Hello,

        ertappt.

        Bis ca. 140.000kByte Dateigröße kann man die Datei gut in ein assoziatives Array einlesen und in ein indiziertes sogar bis zu 200.000kByte.

        Sollte natürlich heißen 140kByte und 200kByte sodass es dann zu einem Speicherbedarf von möglichst nicht mehr als 1MByte für das Array führt. Das ist für PHP kein Problem. Was soll da jenseits von Gut und Böse sein?

        das meinst Du hoffentlich nicht ernst, oder? Selbst wenn Du "Byte" statt "kByte" geschrieben hättest, wären solche Größen jenseits von Gut und Böse.

        Alternativ kann man eine CSV-Datei natürlich auf die klassische Art abarbeiten, also Zeile für Zeile,

        Was genau das ist, was man beim kompletten Einlesen auch tut - mit allen Zeilen, statt nur mit denen, die man braucht, bis das Ergebnis gefunden wurde.

        Aber Zeile für Zeile nacheinander. Über die Buffer-Mechanismen von PHP hatte ich ja nun neulich erst meinen Disput. Das Buffering für die Datei ändert aber nichts an der Tatsache, dass bei zeilenweiser Abarbeitung immer nur eine Zeile (zusätzlich) im Speicherbreich des Scriptes gehalten werden muss für die Auswertung und bei vollständigem Einlesen eben alle Zeilen gleichzeitig.

        Irgendwann könnte dann der beliebte out of memory error kommen, gegen den man ab 4.3.2 Version was tun kann. http://de.php.net/manual/de/function.memory-get-usage.php

        Harzliche Grüße aus http://www.annerschbarrich.de

        Tom

        --
        Fortschritt entsteht nur durch die Auseinandersetzung der Kreativen
        Nur selber lernen macht schlau
        1. Hi,

          Sollte natürlich heißen 140kByte und 200kByte sodass es dann zu einem Speicherbedarf von möglichst nicht mehr als 1MByte für das Array führt. Das ist für PHP kein Problem. Was soll da jenseits von Gut und Böse sein?

          auch wenn die Verwaltung dieser Datenmasse kein Problem darstellen mag - sprich: PHP da noch nicht an seine Grenzen gestoßen ist - muss sie zunächst einmal geladen, analysiert und in ein Speichermodell übersetzt worden sein, sowie der entsprechende Arbeitsspeicher vom Betriebssystem verwaltet werden. Das Laden kompletter Dateien in den Speicher, wenn man nur einen winzigen Ausschnitt derselben braucht, ist _immer_ und in _jeder_ Sprache ein Fehler.

          Was genau das ist, was man beim kompletten Einlesen auch tut - mit allen Zeilen, statt nur mit denen, die man braucht, bis das Ergebnis gefunden wurde.
          Aber Zeile für Zeile nacheinander.

          Mit anschließender Freigabe (genauer gesagt: Wiederverwendung) des Speichers.

          Irgendwann könnte dann der beliebte out of memory error kommen, gegen den man ab 4.3.2 Version was tun kann.

          Workarounds für die Nachteile eines schlechten Konzepts? Ich empfehle, lieber gleich auf den wesentlich besseren Mechanismus zurückzugreifen, nicht mehr Daten zu halten, als man wirklich benötigt. Das ist ein Grundprinzip der Programmierung.

          Cheatah

          --
          X-Self-Code: sh:( fo:} ch:~ rl:° br:> n4:& ie:% mo:) va:) de:] zu:) fl:{ ss:) ls:~ js:|
          X-Self-Code-Url: http://emmanuel.dammerer.at/selfcode.html
          X-Will-Answer-Email: No
          X-Please-Search-Archive-First: Absolutely Yes
          1. Hello,

            Workarounds für die Nachteile eines schlechten Konzepts? Ich empfehle, lieber gleich auf den wesentlich besseren Mechanismus zurückzugreifen, nicht mehr Daten zu halten, als man wirklich benötigt. Das ist ein Grundprinzip der Programmierung.

            Prinzipiell stimme ich Dir da zu. Allerdings halten Mechanismen, wie Caching, Buffering und ähnliche dagegen. Ob nun die Verwendung einer DB die bessere Lösung ist, ist auch von vielen Faktoren abhängig. MySQL speichert z.B. keinesfalls in einem festen Satzformat, sondern mischt innerhalb einer Tabelle verschiedene Satzformate, sodass hier auch immer recht große Einheiten in den Speicher geholt werden müssen. Andere Systeme sind dafür Verschwender auf dem Permentspeichermedium.

            Ob es hier überhaupt eone generelle Vorgehensempfehlung geben kann, wage ich zu bezweifeln.

            Fakt ist jedenfalls, dass in der Praxis CSV-Dateien bis ca. 200kByte "locker" mit der Arraytechnik verarbeitet werden können, und dies auch keine unangemessene Last Für die maschine darstellt. Die sparsamste Methose (nicht für den Speicher, sondern für die Verarbeitungsdauer) ist, die gesamte Datei auf einmal einzulesen, sie dann in ein Array zu zerlegen und zu verarbeiten und dann die Ergebnisse in möglichst nur einer Output-Operation zurückzuliefern. Die IO-Zugriffe (dazu gehört auch echo, wenn man nicht buffert) sind die teuersten.

            Harzliche Grüße aus http://www.annerschbarrich.de

            Tom

            --
            Fortschritt entsteht nur durch die Auseinandersetzung der Kreativen
            Nur selber lernen macht schlau
            1. Hi,

              Prinzipiell stimme ich Dir da zu. Allerdings halten Mechanismen, wie Caching, Buffering und ähnliche dagegen. Ob nun die Verwendung einer DB die bessere Lösung ist, ist auch von vielen Faktoren abhängig.

              ja. Zusammengefasst wäre IMHO folgendes richtig: Das jeweilige Vorgehen ist immer vom individuellen Umfeld und den Bedingungen abhängig. Konform?

              Ob es hier überhaupt eone generelle Vorgehensempfehlung geben kann, wage ich zu bezweifeln.

              Sicher nicht. Ich halte es jedoch für einen schwerwiegenden Fehler, _gerade_ in Unkenntnis der exakten Sachlage das in den meisten Fällen schlechtestmögliche Vorgehen zu empfehlen, zumal in der Pauschalität.

              Fakt ist jedenfalls, dass in der Praxis CSV-Dateien bis ca. 200kByte "locker" mit der Arraytechnik verarbeitet werden können, und dies auch keine unangemessene Last Für die maschine darstellt.

              Dieser Fakt hängt unmittelbar davon ab, was mit "der" Praxis gemeint ist. Ändern sich die Daten beispielsweise stark, oder die Funktion wird viele Male pro Sekunde aufgerufen, oder der Vorgang wird mit vielen Dateien durchgeführt, oder ... (usw.), dann ist dieses Vorgehen ein absoluter Killer.

              Die sparsamste Methose (nicht für den Speicher, sondern für die Verarbeitungsdauer) ist, die gesamte Datei auf einmal einzulesen,

              Erwartest Du die Information statistisch verteilt, potenziell am Ende der Datei, potenziell am Anfang, potenziell gar nicht? Auch(!) hiervon hängt die Lösung ab. Die sparsamste Methode könnte ohne weiteres der Aufruf eines Systemprogramms wie z.B. grep sein. Ich könnte mir sogar den Fall vorstellen, dass die sparsamste Methode darin besteht, die Datei in eine temporäre DB-Tabelle zu übertragen und dort eine Abfrage durchzuführen.

              Nein, das komplette Einlesen einer Datei, von der man nur Bruchstücke benötigt, ist in aller Regel ein Fehler. In Einzelfällen ist es die bestmögliche Lösung, ohne Zweifel. Dieses Vorgehen pauschal zu empfehlen, insbesondere ohne auf die immensen Gefahren hinzuweisen, halte ich jedoch für grob fahrlässig. Das "klassische" Vorgehen, die Daten zeilenweise zu verarbeiten, bis das Ergebnis gefunden wurde, mag im Durchschnitt eine schlechtere Performance bieten - es ist jedoch, wenn jede Zeile nur für sich betrachtet werden muss, _immer_ praktisch völlig gefahrlos.

              Cheatah

              --
              X-Self-Code: sh:( fo:} ch:~ rl:° br:> n4:& ie:% mo:) va:) de:] zu:) fl:{ ss:) ls:~ js:|
              X-Self-Code-Url: http://emmanuel.dammerer.at/selfcode.html
              X-Will-Answer-Email: No
              X-Please-Search-Archive-First: Absolutely Yes
              1. Hello,

                Nein, das komplette Einlesen einer Datei, von der man nur Bruchstücke benötigt, ist in aller Regel ein Fehler. In Einzelfällen ist es die bestmögliche Lösung, ohne Zweifel. Dieses Vorgehen pauschal zu empfehlen, insbesondere ohne auf die immensen Gefahren hinzuweisen, halte ich jedoch für grob fahrlässig. Das "klassische" Vorgehen, die Daten zeilenweise zu verarbeiten, bis das Ergebnis gefunden wurde, mag im Durchschnitt eine schlechtere Performance bieten - es ist jedoch, wenn jede Zeile nur für sich betrachtet werden muss, _immer_ praktisch völlig gefahrlos.

                Es wird wohl nicht zu einer vernünftigen Lösung kommen, wenn Jan sich nicht nochmal zu den Randbedingungen äußert. Wir könnten ohne weiteres das Für und Wider noch über 120 Seiten (im Druck) diskutieren und letztlich doch keine Empfehlung herausarbeiten...

                In sofern stimme ich da mit Dir überein. Außerdem versuche ich immer noch moch daran zu erinnern, wie man solche Probleme zu DOS-Zeiten (ca. 700kByte maximaler RAM für das Programm) geklärt hat. Da war man meistens auf gute Disk-Strategien angewiesen. Das steht natürlich im Widerspruch zu den Methoden bei 256MByte RAM pro Prozess...

                Harzliche Grüße aus http://www.annerschbarrich.de

                Tom

                --
                Fortschritt entsteht nur durch die Auseinandersetzung der Kreativen
                Nur selber lernen macht schlau
                1. Hi,

                  Es wird wohl nicht zu einer vernünftigen Lösung kommen, wenn Jan sich nicht nochmal zu den Randbedingungen äußert. Wir könnten ohne weiteres das Für und Wider noch über 120 Seiten (im Druck) diskutieren und letztlich doch keine Empfehlung herausarbeiten...

                  ich glaube, das kann man als Schlusswort stehen lassen :-)

                  [...] zu DOS-Zeiten (ca. 700kByte maximaler RAM für das Programm)

                  Du meinst wohl eher maximal ca. 632.408 (oder so) Byte, je nachdem, wie man sein System optimiert hatte, inklusive alternativer Tastaturtreiber und was es nicht alles an Schnickschnack gab, um noch zwei Byte zu sparen *g*

                  Cheatah

                  --
                  X-Self-Code: sh:( fo:} ch:~ rl:° br:> n4:& ie:% mo:) va:) de:] zu:) fl:{ ss:) ls:~ js:|
                  X-Self-Code-Url: http://emmanuel.dammerer.at/selfcode.html
                  X-Will-Answer-Email: No
                  X-Please-Search-Archive-First: Absolutely Yes