Manfred: ersetze Zeichen zwischen zwei Zeichen?

Hallo,

ich bin leider ein ziemlicher Anfänger, was reguläre Ausdrücke betrifft, deswegen meine Frage hier:

Ich hab einen String, der eine Reihe von Werten enthält, alle in Anführungsstrichen gesetzt und durch Kommata getrennt.

Wenn ich jetzt die Werte in Variablen speichern möchte, kann ich ja leider nicht nach dem Komma splitten.
Ich müsste also vorher alle Kommata innerhalb der Anführungstrichem durch Punkte ersetzen.
Aus dem Bespiel
"Liste 1","40,32","20,12","12,07"
müsste also werden:
"Liste 1","40.32","20.12","12.07"

Das geht sicherlich durch reguläre Ausdrücke ... aber wie?

Lieben Dank,

Euer Manni

  1. Hallo Manni,

    das geht auch ohne RegEx:

    <?php  
    $a='"Liste 1","40,32","20,12","12,07"';  
    $a=[link:http://de3.php.net/manual/de/function.explode.php@title=explode]('"',$a);  
    for($i=1;$i<[link:http://de3.php.net/manual/de/function.count.php@title=count]($a);$i+=2)  
            $a[$i]=[link:http://de3.php.net/manual/de/function.str-replace.php@title=str_replace](',','.',$a[$i]);  
    $a=[link:http://de3.php.net/manual/de/function.implode.php@title=implode]('"',$a);  
    echo $a;  
    ?>
    

    Gruß aus Berlin!
    eddi

    1. Hallo Eddi,

      das geht auch ohne RegEx:

      auch wenn ich RegEx nicht kann, ist es doch das bessere oder?

      Ich würd schon ganz gerne die "elegantere" Methode verwenden.

      Liebe Grüße,

      Manni

      1. Hallo Manfred.

        auch wenn ich RegEx nicht kann, ist es doch das bessere oder?

        Besser? Nein, finde ich nicht. Du wirst mit Regular Expressions sogar einigen Aufwand mehr haben als mit den anderen hier vorgestellten Methoden. Du möchtest eine verschachtelte Struktur analysieren, und dafür sind Regular Expressions ohne weitere "Hilfsoperationen" ziemlich ungeeignet.

        Ich würd schon ganz gerne die "elegantere" Methode verwenden.

        Eddis Methode ist die Kurzversion eines CVS-Parsers, der von Komma zu Komma scannt und nach dem Einlesen eines Anführungszeichens als erstem Wert alle Folgezeichen (auch Kommata!) bis zum nächsten Anführungszeichen liest. Den kannst du dir natürlich auch selber schreiben.

        Was genau verstehst du aber unter "elegant"? Eddis Skript erledigt deine Aufgabe in zweieinhalb Zeilen -- Replace und Implode sind ja überflüssig, wenn du die Werte wirklich nur extrahieren und dann anderweitig weiterverarbeiten möchtest. Vielleicht nicht das, was du unter elegant verstehst, aber zumindest sehr _kurz_. ;-) Funktioniert allerdings auch nur, wenn tatsächlich _alle_ Werte in Anführungszeichen stehen.

        1. gudn tach!

          auch wenn ich RegEx nicht kann, ist es doch das bessere oder?

          Besser? Nein, finde ich nicht. Du wirst mit Regular Expressions sogar einigen Aufwand mehr haben als mit den anderen hier vorgestellten Methoden.

          pauschal kann man meiner erfahrung nach schlecht die geschwindigkeit von sowas beurteilen.
          ein gegenbeispiel aus juengster zeit: </archiv/2006/4/t127277/#m821481>

          Du möchtest eine verschachtelte Struktur analysieren

          naja, verschachtelungstiefe=1. ist jetzt noch nicht soo verschachtelt.

          , und dafür sind Regular Expressions ohne weitere "Hilfsoperationen" ziemlich ungeeignet.

          1. nicht zwangslaeufig. mit look-aheads und -behinds geht da so einiges.
          2. und was spricht gegen solche hilfsoperationen?

          prost
          seth

          1. 'Nabend seth.

            pauschal kann man meiner erfahrung nach schlecht die geschwindigkeit von sowas beurteilen.

            Hab ich auch gar nicht. Ich rede lediglich vom Aufwand beim Programmieren dieser Geschichte. Um Performance (gemessen in Abarbeitungszeit des Skripts o.ä.) ging es mir überhaupt nicht.

            Du möchtest eine verschachtelte Struktur analysieren

            naja, verschachtelungstiefe=1. ist jetzt noch nicht soo verschachtelt.

            Richtig, aber trotzdem schon mehr Aufwand für RegExps (z.B. mit Assertions, wie du schon selber sagst). Ob die es "eleganter" machen? Ich weiß ja nicht... Jedenfalls schwerer für Manfred, der eigener Aussage nach bisher gar nichts mit Regular Expressions zu tun hatte.

            1. und was spricht gegen solche hilfsoperationen?

            Daß sie in diesem konkreten Fall umfangreicher werden als in deinem Beispiellink. Eingeschlossen werden die Werte nämlich _nicht_ durch zwei unterschiedliche Zeichen (< und >), sondern eben nur die Anführungsstriche. Das verkompliziert die Sache in meinen Augen zumindest so sehr, daß es auch kein großer Schritt mehr zu einem selbstgeschrieben CSV-Parser wäre -- auch wenn dieser sicher ein paar mehr Zeilen Code hätte. ;-)

            Spricht in deinen Augen etwas gegen Eddis oder Toms Lösung?

            1. Hallo seth.

              Mal abgesehen davon, daß ich vorhin nicht Tom sondern dedlfix meinte (bin wohl im falschen Tab gelandet), stelle ich gerade fest, daß das hier ...

              Das verkompliziert die Sache in meinen Augen zumindest so sehr, daß es auch kein großer Schritt mehr zu einem selbstgeschrieben CSV-Parser wäre

              ... zugegebenermaßen etwas übetrieben war. Ich hatte mir die Sache etwas komplizierter vorgestellt als sie eigentlich ist. Hatte auch deinen anderen Beitrag weiter oben vorhin noch nicht entdeckt.

              Also: Kommando zurück!

              Ich hau mich jetzt aufs Ohr. Wird ja offensichtlich langsam Zeit. ;-)

          2. Tachchen,

            auch wenn ich RegEx nicht kann, ist es doch das bessere oder?

            Besser? Nein, finde ich nicht. Du wirst mit Regular Expressions sogar einigen Aufwand mehr haben als mit den anderen hier vorgestellten Methoden.

            pauschal kann man meiner erfahrung nach schlecht die geschwindigkeit von sowas beurteilen.
            ein gegenbeispiel aus juengster zeit: </archiv/2006/4/t127277/#m821481>

            da kann ich Dir aber pauschalisieren, daß Du mehr Probleme und mehr Zeitaufwand mit RegEx beim erstellen/warten hast, als mit einer Prozedur Deiner eigenen Sprache. :)

            Gruß aus Berlin!
            eddi

  2. echo $begrüßung;

    Ich hab einen String, der eine Reihe von Werten enthält, alle in Anführungsstrichen gesetzt und durch Kommata getrennt.
    Wenn ich jetzt die Werte in Variablen speichern möchte, kann ich ja leider nicht nach dem Komma splitten.

    Kommt der String vielleicht aus einer Datei? Dann wäre fgetcsv() eine bessere Methode, diese auszulesen.

    echo "$verabschiedung $name";

    1. Hallo,

      Kommt der String vielleicht aus einer Datei? Dann wäre fgetcsv() eine bessere Methode, diese auszulesen.

      Der String kommt zwar aus einer Datei, aber diese enthält (leider) nicht nur csv-Code. Ich müsste also, um die Funktion zu verwenden, durch die Datei parsen, den CSV-Bereich auslesen und erst in eine Datei speichern, damit ich diese dann wieder mit fgetcsv auslesen kann.
      Das ist noch umständlicher  ;-))

      Liebe Grüße

      1. echo $begrüßung;

        Kommt der String vielleicht aus einer Datei? Dann wäre fgetcsv() eine bessere Methode, diese auszulesen.

        Der String kommt zwar aus einer Datei, aber diese enthält (leider) nicht nur csv-Code. Ich müsste also, um die Funktion zu verwenden, durch die Datei parsen, den CSV-Bereich auslesen und erst in eine Datei speichern, damit ich diese dann wieder mit fgetcsv auslesen kann.
        Das ist noch umständlicher  ;-))

        Ja, aber nur, wenn du das _so_ machst :-)
        Du kannst auch mit den "normalen" Dateilesefunktionen - z.B. mit fgets() - zuerst den Nicht-CSV-Teil lesen. Dann liest du einfach mit dem selben Dateihandle aber mit fgetcsv() weiter bis der CSV-Teil endet und dann gehts wieder mit fgets() weiter ...

        echo "$verabschiedung $name";

  3. gudn tach!

    Ich müsste also vorher alle Kommata innerhalb der Anführungstrichem durch Punkte ersetzen.
    Aus dem Bespiel
    "Liste 1","40,32","20,12","12,07"
    müsste also werden:
    "Liste 1","40.32","20.12","12.07"

    Das geht sicherlich durch reguläre Ausdrücke ... aber wie?

    mit preg_replace('/(".*?")/e', 'strtr("$1", ",", ".")', $str) ginge es bswp., allerdings _muss_ dann ein anfuehrungszeichen immer einen begrenzer darstellen. sowas wie "foo"bar"" waere also nicht mehr erlaubt. je nach anwendungsfall waere dir damit schon geholfen.
    links aus dem php-manual: strtr, preg_replace, pattern modifiers.

    je nach dem, wie die files aussehen, aus denen du den kram einliest, ist der weg ueber die von dedlfix angesprochene methode evtl. effizienter.

    prost
    seth

    1. Hallo,

      for($j=0;$j<100000;$j++){  
              $a=explode('"','"Liste 1","40,32","20,12","12,07","Liste 1","40,32","20,12","12,07","Liste 1","40,32","20,12","12,07"');  
              for($i=1;$i<count($a);$i+=2)  
                      $a[$i]=str_replace(',','.',$a[$i]);  
              $a=implode('"',$a);  
      }
      

      $ time env -i ./x.php

      real    0m4.170s
      user    0m4.132s
      sys     0m0.008s

      for($i=0;$i<100000;$i++)  
              $a=preg_replace('/(".*?")/e', 'strtr("$1", ",", ".")', '"Liste 1","40,32","20,12","12,07","Liste 1","40,32","20,12","12,07","Liste 1","40,32","20,12","12,07"');
      

      $ time env -i ./y.php

      real    0m17.449s
      user    0m17.405s
      sys     0m0.000s

      Testumgebung:

      AMD Athlon(tm) XP 1800+
         RAM 759472 kB

      OS:  GNU/Linux (gentoo) 2.6.16.5
         PHP: 5.1.3-dev CLI

      man sollte nicht verallgemeinern - sicher, aber dies ist mal wieder einer der doch recht typischen Ergebnisse, die mich auch weiterhin davon abhalten werden, diesen Mist einzusetzen.

      Gruß aus Berlin!
      eddi