Tim Walter: ReExp

Hallo Liste

ich habe eine csv Datei in art eines baums, wo aber leider einige verzweigungen doppelt sind.

sieht etwa so aus:
doof;test1;test1;drei
test2;test2;hans;hans;vier
test3;test3;test3;fuenf
test4;test4;hans;peter
karl;tut;tut;lisa
tim;tim ist doof

mein plan ist jeztt die datei zu durchlaufen und alle n-fachen zu entfernen. ergebnis sollte sein:
doof;test1;drei
test2;hans;vier
test3;fuenf
test4;hans;peter
karl;tut;lisa
tim;ist doof

aber ich hab da mit meinen lösungen noch nicht so den erfolg gehabt.
bei der letzten zeile müsste man wohl auch bedenken, das er von hinten anfängt auszutauschen.

mein ansatz war so in der art:
$line=";".$line;
if($line=~m/(;[^;]+){2}/i)
{
  $line=~s/$1//i;
}

der sammelt aber nur die doppelten weg und leider von vorne.
sieht dann nur so aus:
doof;test1;drei
test2;hans;hans;vier
test3;test3;fuenf
test4;hans;peter
karl;tut;lisa
tim ist doof

kann mir einer helfen, oder zumindest mal eine ordentliche (bitte deutschsprachige) Seite nennen, wo man in die irrsinnigen weissheiten des pattern matching eingeführt wird.

Danke ..

cu Tim

  1. Hi,

    kann mir einer helfen, oder zumindest mal eine ordentliche (bitte deutschsprachige) Seite nennen, wo man in die irrsinnigen weissheiten des pattern matching eingeführt wird.

    Regular Expressions helfen Dir nicht, weil Du kein Muster suchst. Du möchtest die Daten inhaltlich analysieren. Hashes könnten Dir hierbei helfen.

    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,

      Regular Expressions helfen Dir nicht, weil Du kein Muster suchst. Du möchtest die Daten inhaltlich analysieren. Hashes könnten Dir hierbei helfen.

      ich suche aber doch nach einem wiederkehrenden muster oder nicht. aber wenn ich da falsch liege werde ich das wohl klassisch schreiben.

      schade..

      cu tim

      1. Hi,

        ich suche aber doch nach einem wiederkehrenden muster oder nicht.

        tust Du das? Wenn ja, dann habe ich Deine Use-Cases fehlinterpretiert. Nach meinem Verständnis suchst Du Dubletten.

        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,

          ich suche aber doch nach einem wiederkehrenden muster oder nicht.

          tust Du das? Wenn ja, dann habe ich Deine Use-Cases fehlinterpretiert. Nach meinem Verständnis suchst Du Dubletten.

          Eine Dublette ist doch ein Muster - da wiederholt sich etwas ...

          (?<=^|;)([^;]+);\1(?=;|$)

          d.h.: lookbehind: entweder Stringanfang oder Trennzeichen, danach ein Wert, danach ein Trennzeichen, danach nochmal derselbe Wert, danach ein lookahead auf Trennzeichen oder Stringende.

          lookbehind + lookahead sind m.E. notwendig, da sonst zum Beispiel bei bla;aber eine Ersetzung zu blaber stattfinden würde.
          (Falls es sich bei den Werten nur um "Wortzeichen" handeln kann, könnten es Wortgrenzen \b auch tun)

          ersetzen durch \1

          sollte m.E. Dubletten in semikolon-getrennten Werten entfernen (Voraussetzung: a;b;a;d gilt nicht, die doppelten Werte müssen aufeinanderfolgen - sonst wird's etwas aufwendiger)
          Sollen auch noch häufigere Vorkommen in einem Durchgang miterledigt werden, müßte es mit

          (?<=^|;)([^;]+)(?:;\1)+(?=;|$)

          klappen.

          cu,
          Andreas

          --
          Warum nennt sich Andreas hier MudGuard?
          Schreinerei Waechter
          O o ostern ...
          Fachfragen unaufgefordert per E-Mail halte ich für unverschämt und werde entsprechende E-Mails nicht beantworten. Für Fachfragen ist das Forum da.
          1. gudn tach!

            tust Du das? Wenn ja, dann habe ich Deine Use-Cases fehlinterpretiert. Nach meinem Verständnis suchst Du Dubletten.

            Eine Dublette ist doch ein Muster - da wiederholt sich etwas ...

            rischdisch.

            (?<=^|;)([^;]+);\1(?=;|$)

            vorsicht, das funzt nicht...
            fuehrt naemlich zu
            "Variable length lookbehind not implemented in regex[...]"

            d.h.: lookbehind: entweder Stringanfang oder Trennzeichen

            kann man durch doppelte negation erreichen:

            (?<![^;])

            in worten: "davor darf kein zeichen kommen, dass kein semikon ist."

            [...] Dubletten

            die schwierigkeit fuer den OP waren vor allem n-fache vorkommnisse fuer n>2.

            prost
            seth

            1. Hi,

              (?<=^|;)([^;]+);\1(?=;|$)

              vorsicht, das funzt nicht...
              fuehrt naemlich zu
              "Variable length lookbehind not implemented in regex[...]"

              kann man durch doppelte negation erreichen:

              Oder durch zwei negative lookbehinds, einen für den Stringanfang, einen für das Trennzeichen ...

              cu,
              Andreas

              --
              Warum nennt sich Andreas hier MudGuard?
              Schreinerei Waechter
              O o ostern ...
              Fachfragen unaufgefordert per E-Mail halte ich für unverschämt und werde entsprechende E-Mails nicht beantworten. Für Fachfragen ist das Forum da.
              1. gudn tach!

                (?<=^|;)([^;]+);\1(?=;|$)

                vorsicht, das funzt nicht...
                fuehrt naemlich zu
                "Variable length lookbehind not implemented in regex[...]"

                kann man durch doppelte negation erreichen:

                Oder durch zwei negative lookbehinds, einen für den Stringanfang, einen für das Trennzeichen ...

                ¿zwei negative?

                mach mal 'n beispiel.

                prost
                seth

                1. Hi,

                  Oder durch zwei negative lookbehinds, einen für den Stringanfang, einen für das Trennzeichen ...
                  ¿zwei negative?

                  Ich sollte so früh am Morgen nicht posten. Zwei positive natürlich.

                  cu,
                  Andreas

                  --
                  Warum nennt sich Andreas hier MudGuard?
                  Schreinerei Waechter
                  O o ostern ...
                  Fachfragen unaufgefordert per E-Mail halte ich für unverschämt und werde entsprechende E-Mails nicht beantworten. Für Fachfragen ist das Forum da.
                  1. gudn tach!

                    Oder durch zwei negative lookbehinds, einen für den Stringanfang, einen für das Trennzeichen ...
                    ¿zwei negative?

                    Ich sollte so früh am Morgen nicht posten. Zwei positive natürlich.

                    ¿zwei positive? ;-)

                    die wuerden einer UND-verknuepfung gleichkommen, aber nicht einer ODER-verknuepfung.

                    prost
                    seth

      2. Hell-O!

        Hashes könnten Dir hierbei helfen.
        ich suche aber doch nach einem wiederkehrenden muster oder nicht.

        Ich stimme Cheatah zu, dass Reguläre Ausdrücke hier nicht nötig sind. Eine Möglichkeit wäre, jede Zeile zu splitten, jeden einzelnen Eintrag als Hash-Schlüssel zu verwenden. Damit entfallen alle Mehrfacheinträge automatisch, da Hash-Schlüssel immer eindeutig sein müssen:

        while(<DATEI>) {  
          # wir brauchen einen frischen Hash  
          my %unique;  
          # Hash-Slice mit den Einzelwerten  
          # Mehrfacheinträge verschwinden  
          @unique{ split(/;/, $string) } = ();  
          # Kontrollausgabe  
          print join ';', (keys %seen);  
        }
        

        Statt der print-Anweisung kannst du die bereinigten Werte natürlich auch speichern oder gleich wegschreiben oder was immer du damit tun willst.

        Siechfred

        --
        Hier könnte Ihre Werbung stehen.
        Swiss Strolli Rider || Die neue 1%-Regelung
        1. Hell-O Ingrid!

          Bevor es jemand anderes merkt:

          @unique{ split(/;/, $string) } = ();

          Muss natürlich heißen:

          @unique{ split(/;/, $_) } = ();

          Siechfred

          --
          Hier könnte Ihre Werbung stehen.
          Swiss Strolli Rider || Die neue 1%-Regelung
        2. gudn tach!

          Ich stimme Cheatah zu, dass Reguläre Ausdrücke hier nicht nötig sind.

          er sagte nicht, dass sie nicht noetig seien, sondern, dass sie nicht helfen wuerden und lag damit falsch.

          Eine Möglichkeit wäre, jede Zeile zu splitten, jeden einzelnen Eintrag als Hash-Schlüssel zu verwenden. Damit entfallen alle Mehrfacheinträge automatisch, da Hash-Schlüssel immer eindeutig sein müssen:

          war auch mein erster gedanke, aber unter den vom OP genannten voraussetzungen bzgl. der verarbeitung von "tim;tim ist doof" wuerde das schon wieder eher haarig werden.

          prost
          seth

  2. gudn tach!

    sieht etwa so aus:
    doof;test1;test1;drei
    test2;test2;hans;hans;vier
    test3;test3;test3;fuenf
    test4;test4;hans;peter
    karl;tut;tut;lisa
    tim;tim ist doof

    kommen etwaige mehrfache denn immer direkt hintereinander vor?

    mein plan ist jeztt die datei zu durchlaufen und alle n-fachen zu entfernen. ergebnis sollte sein: [...]
    tim;ist doof

    bei der letzten zeile müsste man wohl auch bedenken, das er von hinten anfängt auszutauschen.

    und was sollte im fall
      tim ist doof;tim
    passieren? nix? oder tritt sowas nicht auf?

    mein ansatz war so in der art:
    $line=";".$line;
    if($line=~m/(;[^;]+){2}/i)
    {
      $line=~s/$1//i;
    }

    der sammelt aber nur die doppelten weg

    bei diesem ansatz muesstest du dann bloss aus dem "if" ein "while" machen. (allerdings behebt das noch nicht die anderen probleme.)

    und leider von vorne.

    hmm, noe.
    aus
      tim;tim ist doof
    matcht /(;[^;]+){2}/
      $1=";tim ist doof"

    je nach antwort auf meine oben gestellten fragen, wird dir evtl. die folgende variation deines ansatzes weiterhelfen:

    for my $line (@lines){  
      $line=';'.$line.';';  
      #while($line=~/(;[^;]+)\1/i){  
      #  $line=~s/($1)$1+./$1;/i;  
      #}  
      #oder u.u. besser mit posisionsmerker:  
      while($line=~/(;[^;]+)(?=\1)/ig){  
        $line=~s/\G$1+./;/i;  
      }  
      $line=substr($line,1,-1);  
      print $line."\n";  
    }
    

    zumindest kommt damit fuer das gegebene beispiel genau das raus, was rauskommen soll.

    kann mir einer helfen, oder zumindest mal eine ordentliche (bitte deutschsprachige) Seite nennen, wo man in die irrsinnigen weissheiten des pattern matching eingeführt wird.

    ich kenne nichts gescheites auf deutsch. die deutschen seiten, die ich kenne, knabbern nur an oberflaechlichkeiten oder winzigen ausschnitten der details.
    aber bei regexps ist imho das verstehen einer _englischen_ dokumentation vernachlaessigbar leicht im ggs. zum inhalt, also den regexps selbst.
    naja, und versuche, sowas wie "zero-width negative look-behind assertion" gescheit zu uebersetzen sind imho schlichtweg zum scheitern verurteilt. "nach hinten blickende negativ-aussagen mit nulllaenge"?
    isch glaub isch muss bresche!
    iow: ok, etwas allumfassendes kann es gar nicht geben, aber auf englisch sind viel mehr nuetzliche information ueber regexps zu finden als auf deutsch. und weil regexps so toll sind, tendiere ich sogar zu der meinung, dass sie alleine grund genug sind, sich mal naeher mit der englischen sprache zu befassen, um sie besser studieren zu koennen.

    trotzdem: ein sehr gutes buch soll die deutsche uebersetzung von "mastering regular expressions" (http://www.oreilly.de/catalog/regex2ger/) sein.

    prost
    seth