Glory: Regex: bestimmte Links aus Quellcode extrahieren

Hallo.

Ich möchte aus dem HTML Quellcode einer Seite ein paar Links extrahieren, indem ich alle Zeichen außer den den Links lösche.
Dazu möchte ich die Suchen-und-Ersetzen-Funktion von JEdit unter mithilfe von regulären Ausdrücken verwenden.

Die Syntax der Links, die ich haben möchte, sieht in etwa so aus (ohne Delimeter):
"http://seite.*"
Ich suche also alle Links die mit einem Anführungszeichen beginnen dann mit http://seite weitergehen, dann beliebig viele verschiedene Zeichen enthalten und schließlich wieder mit einem Anführungszeichen enden.
Probiert hatte ich folgendes:
[^"http://seite.*"] - also alles, was nicht diesem Link entspricht durch nichts ersetzen und somit löschen.
Allerdings sind die Ausdrücke wohl "gierig" und hören erst beim letzten Anführungszeichen in der Zeile auf. In SELFHTML habe ich gefunden, dass man nun hinter den Ausdruck ein Fragezeichen setzen soll, damit die Ausdrücke genügsam sind:
[^"http://seite.*"]?
[^"http://seite.*"?]
Sowohl die erste als auch die zweite Variante bringen nicht das erwünschte Ergebnis, sondern es werden alle Zeichen nach dem ersten Anführungszeichen gelöscht. Interpretiert JEdit das Fragezeichen anders?
Bitte helft mir, die Links zu extrahieren.
Mfg, Glory

  1. Sup!

    [^"http://seite.*"]?

    Das Fragezeichen muss hinter dem "Quantifikator" stehen, der "nicht-gierig" gemacht werden soll, also hinter dem *; der Stern bedeutet ja "0 bis unendlich viele".

    *? bedeutet dann: 0 bis unendlich viele, aber möglichst wenige.

    [^"http://seite.*?"]

    Gruesse,

    Bio

    --
    Never give up, never surrender!!!
    1. Das Fragezeichen muss hinter dem "Quantifikator" stehen, der "nicht-gierig" gemacht werden soll, also hinter dem *; der Stern bedeutet ja "0 bis unendlich viele".

      *? bedeutet dann: 0 bis unendlich viele, aber möglichst wenige.

      [^"http://seite.*?"]

      Hallo Bio.
      Hier mal ein etwas vereinfachtes Beispiel:

      -------------------------
      aaaaaaaaaaaaa#XXX#aaaaaaaa#YYYY#aaaaaaaaaaaaaaaaaaaa
      aaaaaaaaaaaaaaaaaaaa#ZZZZZ#aaaaaaaaaaaaaaaaaaaaaaaaa
      -------------------------

      Aus diesen Zeichen (ohne die ----) soll am ende #XXX##YYYY##ZZZZZ# werden.
      Mein Regex sieht nun folgendermaßen aus:
      [^#.*?#] ersetzen mit nichts.
      Die Ausgabe von JEdit ist dann:

      Es wurden also auch die Zeichen innerhalb der ## ersetzt.
      Hab ich immernoch einen Fehler im Regex?

      1. Hallo Glory!

        Wie sieht Dein gesamter Ausdruck aus? Ich kenne JEdit nicht, aber aus der RegEx-Syntax, der ich bisher kenne, sind unter eckigen Klammern Zeichenklassen definiert. Was bedeuten sie also bei Dir?

        [^#.*?#]

        würde bedeuten: Match alles aus einer Zeichenklasse, die aus keinem Rautezeichen, beliebig, aber möglichst wenig aller möglichen Zeichen und einem Rautezeichen besteht

        Das heißt, alles wird ersetzt, bis auf "kein Rautezeichen". Kein Rautezeichen wird ersetzt, du hast in deinem String sechs davon, sie werden ausgegeben. Perl-Test:

        perl -w

        use strict;
        my $str = "aaaaaaaaaaaaa#XXX#aaaaaaaa#YYYY#aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
        aaa#ZZZZZ#aaaaaaaaaaaaaaaaaaaaaaaaa";
        $str =~ s/[^#.*?#]//g;
        print $str;
        ^Z

        Die gleiche Ausgabe (die Du nicht wünschst) erreichst Du durch:

        $str =~ s/[^#]//g;

        Du willst aber die Rautezeichen UND den darin enthaltenen Inhalt:

        Aus diesen Zeichen (ohne die ----) soll am ende #XXX##YYYY##ZZZZZ# werden

        Das heißt, Du willst alles, was weder vor noch hinter einem Rautezeichen steht (hier also alles ausser den vielen "a").

        use strict;
        my $str = "aaaaaaaaaaaaa#XXX#aaaaaaaa#YYYY#aaaa
        aaa#ZZZZZ#aaaaaaaaaaaaaaaaaaaaaaaaa";
        $str =~ s/.+?(#\w+#)/$1/g;
        print $str;
        ^Z
        #XXX##YYYY##ZZZZZ#aaaaaaaaaaaaaaaaaaaaaaaaa

        Die "a"s am Ende bekomme ich nicht weg - bin ja noch kein RegExPert (*g*) und außerdem brauchst Du Deinen Ausdruck sicher, um etwas anders als "a"s weg zu bekommen. Irgendwas mit zero-width Assertions muss noch darin, aber so weit bin ich noch nicht, dass ich das meistere. Hoffe, es ist schon mal ein Ansatz für Dich, weiter zu forschen.

        Viele Grüße aus Frankfurt/Main,
        Patrick

        --

        _ - jenseits vom delirium - _
        [link:hatehtehpehdoppelpunktslashslashwehwehwehpunktatomicminuseggspunktcomslash]
        Nichts ist unmöglich? Doch!
        Heute schon gegökt?
        1. Hi,

          Wie sieht Dein gesamter Ausdruck aus? Ich kenne JEdit nicht, aber aus der RegEx-Syntax, der ich bisher kenne, sind unter eckigen Klammern Zeichenklassen definiert. Was bedeuten sie also bei Dir?

          [^#.*?#]
          würde bedeuten: Match alles aus einer Zeichenklasse, die aus keinem Rautezeichen, beliebig, aber möglichst wenig aller möglichen Zeichen und einem Rautezeichen besteht

          Nein, das würde bedeuten: Matche genau ein Zeichen, das nicht Raute, Punkt, Stern oder Fragezeichen ist.
          Quantifier-Zeichen haben innerhalb einer Zeichenklasse keine Bedeutung.

          cu,
          Andreas

          --
          Warum nennt sich Andreas hier MudGuard?
          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. Hallo MudGuard!

            Quantifier-Zeichen haben innerhalb einer Zeichenklasse keine Bedeutung.

            Ja, danke für die Berichtigung. Ich tappe da noch in diese Falle...

            Viele Grüße aus Frankfurt/Main,
            Patrick

            --

            _ - jenseits vom delirium - _
            [link:hatehtehpehdoppelpunktslashslashwehwehwehpunktatomicminuseggspunktcomslash]
            Nichts ist unmöglich? Doch!
            Heute schon gegökt?
          2. Quantifier-Zeichen haben innerhalb einer Zeichenklasse keine Bedeutung.

            Nicht? Das würde dann so einiges erklären. =/
            Dann hab ich aber nicht die geringsten Idee, wie ich das ganze sonst lösen könnte.

            1. Sup!

              Warum willst/musst Du JEdit benutzen, um die Regular Expressions auszuwerten? Kann JEdit beim Ersetzen nicht auf "Backreferences" zurückgreifen, also gespeicherte Teile vom zu ersetzenden Text, den man vorher gematcht hat?

              Gruesse,

              Bio

              --
              Never give up, never surrender!!!
        2. Die "a"s am Ende bekomme ich nicht weg

          Ich würde anders herangehen:

          my $str = "aaaaaaaaaaaaa|XXX|aaaaaaaa|YYYY|aaaaaaa|ZZZZZ|aaaaaaaaaaaaaaaaaaaaaaaaa";  
          my @matches = $str =~ /(\|[^a]+?\|)/g;  
          print join '', @matches;
          

          Nur so als Vorschlag, mit s/// fällt mir offen gestanden nichts vernünftiges ein.

          Siechfred

          1. Hallo Siechfred!

            my $str = "aaaaaaaaaaaaa|XXX|aaaaaaaa|YYYY|aaaaaaa|ZZZZZ|aaaaaaaaaaaaaaaaaaaaaaaaa";

            my @matches = $str =~ /(|[^a]+?|)/g;
            print join '', @matches;

            
            > Nur so als Vorschlag, mit s/// fällt mir offen gestanden nichts vernünftiges ein.  
              
            Danke, führt auf jeden Fall zum Ergebnis. Meine Versuche einer direkten Substitution führten ebenfalls zu nichts...  
              
            Viele Grüße aus Frankfurt/Main,  
            Patrick
            
            -- 
            ![](http://www.atomic-eggs.com/zensstop.gif)  
              
            \_ - jenseits vom delirium - \_  
              
            [[link:hatehtehpehdoppelpunktslashslashwehwehwehpunktatomicminuseggspunktcomslash](http://www.atomic-eggs.com/)]  
            Nichts ist unmöglich? [Doch!](http://www.atomic-eggs.com/cwi/cwi_4.shtml)  
            Heute schon ge[gök](http://goek.atomic-eggs.com/goek_goek.html)t?
            
  2. gudn tach!

    vorab:
    ich kenne den regexp-funktionumfang und die syntax von jedit nicht. ich kann dir bloss sage, wie ich das problem loesen wuerde...

    Ich möchte aus dem HTML Quellcode einer Seite ein paar Links extrahieren, indem ich alle Zeichen außer den den Links lösche.

    in unix (oder in einem modifizierten windows) im cli ginge das z.b. so:

    grep -oP 'http://seite[^"\n ]*' test.dat

    der parameter o steht fuer "gib alles zurueck, was gematcht wird, aber nicht immer die komplette zeile."

    P steht dafuer, dass perl-regexp-syntax verwendet wird.

    der regexp
      http://seite[^"\n ]*
    matcht "http://seite" gefolgt von beliebig vielen (dafuer ist "*") zeichen aus der zeichenklasse [^"\n ], also "alles, was weder doppeltes anfuehrungszeichen noch leerzeichen noch zeilenumbruch ist".

    test.dat ist hier die zu durchsuchende datei.

    fuer windows kannst du grep z.b. auf http://gnuwin32.sourceforge.net/ runterladen.

    wenn jedit ein guter texteditor ist, laesst er es zu, externe scripts einzubinden. falls er das nicht zulaesst, empfehle ich den umstieg.
    ich nutze vim, weil der eine aehnliche regexp-syntax wie perl hat und (zurzeit) sogar noch mehr kann.

    prost
    seth

    1. Sup!

      Das Problem ist ja, dass er im JEdit die Sachen rauswerfen will, die *kein* Link sind, was ungleich schwerer ist als alle Links zu extrahieren. Vielleicht ist es sogar unmöglich, schließlich kann auch im Fließtext etwas stehen, was wie ein Link aussieht.

      Vielleicht würde es sogar gehen, mit einer Wüste von negativen Lookbehinds und Lookaheads, aber ich habe keine Ahnung, ob JEdit das unterstützt.

      Gruesse,

      Bio

      --
      Never give up, never surrender!!!
      1. gudn tach!

        Das Problem ist ja, dass er im JEdit die Sachen rauswerfen will, die *kein* Link sind, was ungleich schwerer ist als alle Links zu extrahieren.

        aeh, wo genau ist da der unterschied?

        prost
        seth

        1. Sup!

          Der Unterschied ist, dass

          s/bla//g

          alle "bla" aus einem Text rauswirft.

          Aber wie wirft man alles raus, was nicht "bla" ist?

          s/Alles-nur-nicht-bla//g

          ?!?

          Gruesse,

          Bio

          --
          Never give up, never surrender!!!
          1. Aber wie wirft man alles raus, was nicht "bla" ist?

            Mal auf den Ausgangsfall gemünzt (Perl-Syntax):

            my $text = '<h1>Ueber</h1><p style="foo">foo<em>bar</em><br>baz<strong>bum!</p>';  
            print $text, "\n";  
            $text =~ s/<(?!\/?(br|p)).+?>//ig;  
            print $text;
            

            Fehlt nur noch die Ersetzung für die unerwünschten Attribute. Eleganter geht's natürlich immer :)

            Siechfred

            1. Mal auf den Ausgangsfall gemünzt (Perl-Syntax):

              Ähm, ich war im falschen Film, mein Code passt wohl besser in diesen Thread.

              Siechfred

              1. Hallo Siechfred!

                Ähm, ich war im falschen Film, mein Code passt wohl besser in diesen Thread.

                Es sei Dir verziehen, Tipps zu RegExps sind überall willkommen ;)

                Ähm, öhm, wie bekomme ich nun Glorys a-Schwanz weg, da unten?

                Viele Grüße aus Frankfurt/Main,
                Patrick

                --

                _ - jenseits vom delirium - _
                [link:hatehtehpehdoppelpunktslashslashwehwehwehpunktatomicminuseggspunktcomslash]
                Nichts ist unmöglich? Doch!
                Heute schon gegökt?
          2. gudn tach!

            Der Unterschied ist, dass

            s/bla//g

            alle "bla" aus einem Text rauswirft.

            Aber wie wirft man alles raus, was nicht "bla" ist?

            s/Alles-nur-nicht-bla//g

            ?!?

            das ist was anderes, ja, aber ich zitiere noch mal:

            Das Problem ist ja, dass er im JEdit die Sachen rauswerfen will, die *kein* Link sind, was ungleich schwerer ist als alle Links zu extrahieren.

            wir haben die nichtleere menge M. alle elemente lassen sich in zwei gruppen unterteilen, naemlich "link" oder "nicht-link". wenn ich nun alles extrahiere, was ein "link" ist, so erhalte ich alle links. wenn ich nun aber von der ursprungsmenge alles loesche, was kein link ist, bleiben schliesslich auch alle links erhalten.
            das ergebnis ist dasselbe. -> kein unterschied.

            prost
            seth

            1. Sup!

              wir haben die nichtleere menge M. alle elemente lassen sich in zwei gruppen unterteilen, naemlich "link" oder "nicht-link". wenn ich nun alles extrahiere, was ein "link" ist, so erhalte ich alle links. wenn ich nun aber von der ursprungsmenge alles loesche, was kein link ist, bleiben schliesslich auch alle links erhalten.
              das ergebnis ist dasselbe. -> kein unterschied.

              Aber wie machst Du das mit einem regulären Ausdruck?

              Okay, Du kannst vielleicht s/(?:.*?(...LINK...))*.*?$/\1/g versuchen, aber möglicherweise unterstützt JEdit ja nichtmal Backreferences in seiner RegExp-Engine bzw. seiner Suchen/Ersetzen Funktion.

              Gruesse,

              Bio

              --
              Never give up, never surrender!!!
              1. gudn tach!

                Aber wie machst Du das mit einem regulären Ausdruck?

                die (zugegeben) pragmagischere frage ist: warum will man es sich so kompliziert (beachte vor allem die mathematiker-loesung) machen.

                Okay, Du kannst vielleicht s/(?:.*?(...LINK...))*.*?$/\1/g versuchen

                wuerde schiefgehen, sobald mehr als ein link pro zeile stehen wuerde.
                man koennte es aufteilen:

                1. s/^/A /gm;
                2. s/($linkpattern)/\n$1\nA/gm;
                3. s/^A.*\n+//gm;

                oder statt 2. (ohne backrefs)
                2a. s/(?=$linkpattern)/\n/g;
                2b. s/(?<=$linkpattern)/\nA/g;

                , aber möglicherweise unterstützt JEdit ja nichtmal Backreferences in seiner RegExp-Engine bzw. seiner Suchen/Ersetzen Funktion.

                deswegen bleibe ich dabei, dass man einfach grep dafuer benutzen sollte oder halt perl:

                grep /$linkpattern/, split /($linkpattern)/, $str;

                prost
                seth

                1. Sup!

                  Okay, Du kannst vielleicht s/(?:.*?(...LINK...))*.*?$/\1/g versuchen

                  wuerde schiefgehen, sobald mehr als ein link pro zeile stehen wuerde.

                  (?:.*?(...LINK...))*

                  matcht aber mehrmals pro Zeile?

                  Gruesse,

                  Bio

                  --
                  Never give up, never surrender!!!
                  1. gudn tach!

                    (?:.*?(...LINK...))*

                    matcht aber mehrmals pro Zeile?

                    kannst du einfach ausprobieren:

                    ~~~perl $_ = 'foobarbaz';
                      s/^(.*?(a))+/$2/;
                      print 'matched: ', $&, "\n";
                      print '     $1: ', $1, "\n";
                      print '     $: ', $, "\n";

                      
                    ausgabe:  
                      
                      matched: foobarba  
                           $1: rba  
                           $\_: az  
                      
                    denn /^(.\*?(a))+/ matcht "foobarba", wegen dem "+".  
                      
                    prost  
                    seth