Gartenzaunler: RegEx-Problem

Hi!

Ich arbeite gerade an einem Gästebuch. Dabei möchte ich dem Benutzer die Möglichkeit geben, Links und Bilder einzufügen. Für die Formatierung von Links habe ich mir das SELFForum als Vorbild genommen.
Beispielsweise habe ich einen Link zu Google mit dem Linktext "Google": [link=http://www.google.de@title=Google]. An die URL und den Titel komme ich, indem ich zuerst das "[link=" entferne und anschließend "]". Danach splitte ich an "@title=". Danach habe ich den Link und den Titel.

Jetzt muss ich aber anschließend den kompletten Link rausschmeissen um ihn durch einen HTML-Link zu ersetzen. Wie kann ich diesen kompletten Link per Regulären Ausdruck rauswerfen?

Ich muss den Teil-String [link= finden. Also:
[link=

Danach suche ich beliebige Wort-Zeichen (a-z, A-Z, ä, ö, ü, Ä, Ö, Ü, 0-9 und der Unterstrich). Also:
\w

Zum Schluss suche ich die abschließende eckige Klammer. Also
]

Das würde doch folgenden Pattern ergeben:
[link=\w]

Mein Code dazu sieht so aus:

string input = "[link=http://www.google.de@title=Google]";
link = Regex.Replace(input, @"[link=\w]", "");
MessageBox.Show(link);

Allerdings wird mir nur der komplette String ausgegeben. Ohne dass etwas ersetzt wurde.

Könnt ihr mir da auf die Sprünge helfen?
Viele Grüße!

  1. Hi Gartenzaunler!

    Danach suche ich beliebige Wort-Zeichen (a-z, A-Z, ä, ö, ü, Ä, Ö, Ü, 0-9 und der Unterstrich). Also:
    \w

    Eine URL kann aber auch noch andere Zeichen enthalten!

    Zum Schluss suche ich die abschließende eckige Klammer. Also
    ]

    Vielleicht "]"? =)

    string input = "[link=http://www.google.de@title=Google]";
    link = Regex.Replace(input, @"[link=\w]", "");
    MessageBox.Show(link);

    Was ist das denn für eine Programmiersprache? Delphi?

    MfG H☼psel

    --
    "It's amazing I won. I was running against peace, prosperity, and incumbency."
    George W. Bush speaking to Swedish Prime Minister unaware a live television camera was still rolling, June 14, 2001
    Selfcode: ie:% fl:( br:> va:) ls:& fo:) rl:? n4:& ss:| de:] js:| ch:? sh:( mo:) zu:)
    1. Hi Hopsel!

      Danach suche ich beliebige Wort-Zeichen (a-z, A-Z, ä, ö, ü, Ä, Ö, Ü, 0-9 und der Unterstrich). Also:
      \w
      Eine URL kann aber auch noch andere Zeichen enthalten!

      Oh, beim genaueren Überlegen: Klar. Dann ersetze ich w durch einen Punkt, oder?

      Zum Schluss suche ich die abschließende eckige Klammer. Also
      ]
      Vielleicht "]"? =)

      Hmm... Das funktioniert bei mir leider nicht so, wie ich es mir vorstelle.

      string input = "[link=http://www.google.de@title=Google]";
      link = Regex.Replace(input, @"[link=\w]", "");
      MessageBox.Show(link);
      Was ist das denn für eine Programmiersprache? Delphi?

      Viel schlimmer: C# ;-))

      Das hier...

      string input = "[link=http://www.google.de@title=Google]";
      link = Regex.Replace(input, @"[link=.]", "");
      MessageBox.Show(link);

      ... funktioniert leider immer noch nicht =(

      Danke für deine Hilfe!
      Kannst du mir weiterhelfen?

      1. Hi Gartenzaunler!

        Das hier...
        string input = "[link=http://www.google.de@title=Google]";
        link = Regex.Replace(input, @"[link=.]", "");
        MessageBox.Show(link);
        ... funktioniert leider immer noch nicht =(

        Jetzt maskierst du den Punkt. Wieso?

        Außerdem hat Beat auch recht: Du lässt im Moment auch invalide URLs zu.

        MfG H☼psel

        --
        "It's amazing I won. I was running against peace, prosperity, and incumbency."
        George W. Bush speaking to Swedish Prime Minister unaware a live television camera was still rolling, June 14, 2001
        Selfcode: ie:% fl:( br:> va:) ls:& fo:) rl:? n4:& ss:| de:] js:| ch:? sh:( mo:) zu:)
        1. Hallo!

          Jetzt maskierst du den Punkt. Wieso?

          Weil ich dachte, ich müsste es markieren, allerdings ist das Quatsch.

          Außerdem hat Beat auch recht: Du lässt im Moment auch invalide URLs zu.

          Ich wollte erstmal Schritt für Schritt vorgehen und nicht alles überstürzen. Außerdem hat das Finden des gesamten Links inkl. Linktext (noch) nichts mit der Überprüfung der URL zu tun. Das erfolgt ja dann einen Schritt weiter (beim Splitten).

          string input = "[link=http://www.google.de@title=Google]";
          link = Regex.Replace(input, @"[link=.]", "");
          MessageBox.Show(link);

          Ausgegeben wird immer noch:
          [link=http://www.google.de@title=Google]

          Ich bin echt verzweifelt =(

          Viele Grüße

          1. string input = "[link=http://www.google.de@title=Google]";
            link = Regex.Replace(input, @"[link=.]", "");
            MessageBox.Show(link);

            Hi
            versuch's mit

            link = Regex.Replace(input, @"[link=.................................]", "");

            Achte auf die Anzahl Punkte ;)

            Ausgegeben wird immer noch:
            [link=http://www.google.de@title=Google]

            Ich bin echt verzweifelt =(

            Und was sagt deine C# Dokumentation?
            Steht dort geschrieben: "Anfänger erkundigen sich am besten im Selfhtml-Forum, welche Art von RE-Krimskrams funzt" ?

            mfg Beat

            --
            Woran ich arbeite:
            X-Torah
            ><o(((°>           ><o(((°>
               <°)))o><                     ><o(((°>o
            1. Hallo!

              versuch's mit

              link = Regex.Replace(input, @"[link=.................................]", "");

              Achte auf die Anzahl Punkte ;)

              Ah, okay. Den Hinweis hab ich verstanden :)

              Ich habe jetzt etwas zusammengeschraubt, das zu laufen scheint:

              (https?://)?(www.)?[\da-zA-ZÄÖÜ.@:]*.[a-zA-Z]{2,4}[\da-zA-ZÄÖÜ.!#$%&'()\*+,/:;=?@[]]

              ist das so in Ordnung? Oder haltet ihr diese RegEx für falsch?

              Danke und Ciaooo

              1. (https?://)?(www.)?[\da-zA-ZÄÖÜ.@:]*.[a-zA-Z]{2,4}[\da-zA-ZÄÖÜ.!#$%&'()\*+,/:;=?@[]]

                ist das so in Ordnung? Oder haltet ihr diese RegEx für falsch?

                (https?://)?

                Du meinst, du akzeptierst auch relative Pfade?

                (www.)?

                und was ist mit
                subdom.example.org?

                [\da-zA-ZÄÖÜ.@:]*

                Eine 2nd level Domain besteht aus mindestens einem Zeichen
                Entweder du akzeptierst nur [A-Za-z0-9_]
                oder du akzeptierst alle Zeichen ausser [^/.]
                .
                [a-zA-Z]{2,4}

                und was ist mit
                   .museum
                etc?
                [a-zA-Z]{2,6}
                wäre angemessener für eine TLD

                dann haben wir an diesem Punkt aber auch IPs
                123.156.1.1
                eventuell mit Port
                123.156.1.1:8080

                [\da-zA-ZÄÖÜ.!#$%&'()\*+,/:;=?@[]]

                Dieser Salat steht wohl für Pfad, Querystring und Fragment

                Ich würde einen anderen Ansatz nehmen

                https?://[^/\s]+

                Dies umfasst alles bis zum beginn des Pfades.
                Wesentlich ist, dass eine Authority keinen Whitespace \s und keinen / enthalten darf. Eventuell auch eine Reihe anderer Zeichen nicht.
                Wir können die erlaubten zeichen auch sumarisch bezeichnen

                [A-Za-z0-9_.:%-] das @ lasse ich mal weg in der Annahme, dass User@Password nicht gesendet wird

                https?://[A-Za-z0-9_.:%-]+

                Ein Pfad ist optional und hat optional eine Pfadangabe mit Query und Fragment.

                (/(pfad+query+fragment)?)?

                Ein Pfad ist simpel ausgedrückt alles, was weder Whitespace noch ein ? noch ein # ist.

                (/([^\s#?]+)?(query+fragment)?)?

                Ein query ist etwas komplexer, weil da verschiedene Delimiter erlaubt sind.
                Aber wir können vorwärtsschauend sagen, dass ein Querystring alles ausser Whitespace und # ist, aber mit ? beginnt

                (/([^\s#?]+)?(?[^\s#]+?)?(fragment)?)?

                Ein Fragment beginnt mit # und hat dann nonwhitespace zur Folge. HTML stellt an ein Fragment zusätzliche Anforderungen, die uns aber hier egal sein können

                (/([^\s#?]+)?(?[^\s#]+?)?(#[^\s]+)?)?

                Das ganze ist nun:
                https?://[A-Za-z0-9_.:%-]+(/([^\s#?]+)?(?[^\s#]+?)?(#[^\s]+)?)?

                nun haben wir aber ein problem meit denen Delimiter [ ], welche im Pattern nicht vorkommen dürfen. Entweder wie integrieren diese zeichen als verbotene Zeichenklasse:

                https?://[A-Za-z0-9_.:%-]+(/([^\s#?[]]+)?(?[^\s#[]])?(#[^\s[]]+)?)?

                oder wir verwenden non greedy Quantifier
                +?  *?  ??
                https?://[A-Za-z0-9_.:%-]+?(/([^\s#?]+?)?(?[^\s#]+?)?(#[^\s]+?)?)?
                wobei wir nun die äussere Schicht ergänzen können und gleichzeitig das zu suchende matchen
                <(matche dies)>

                [link=(https?://[A-Za-z0-9_.:%-]+?(/([^\s#?]+?)?(?[^\s#]+?)?(#[^\s]+?)?)?]

                Jetzt noch das optionale label.
                Dieses beginnt mit @title= und hat irgend etwas 'non greedy'
                (@title=.+?)?

                zusammen

                [link=(https?://[A-Za-z0-9_.:%-]+?(/([^\s#?]+?)?(?[^\s#]+?)?(#[^\s]+?)?)?(@title=.+?)?]

                Eine Perl version zur besseren Lesbarkeit

                m/[
                  link=
                  (
                    https?://
                    [A-Za-z0-9_.:%-]+?
                    (/
                      ([^\s#?]+?)?
                      (?[^\s#]+?)?
                      (#[^\s]+?)?
                    )?
                    (@title=.+?)?
                  ]/x

                Und nun matchen:
                () speichert in $1 - $9
                (?:) speichert nicht
                Ich speichere die Url und das label separat, vermeide aber das Speichern aller sepraten url teile

                m/[
                  link=
                  (
                    https?://
                    [A-Za-z0-9_.:%-]+?
                    (?:/
                      (?:[^\s#?]+?)?
                      (?:?[^\s#]+?)?
                      (?:#[^\s]+?)?
                    )?
                    (@title=.+?)?
                  ]/<a href="$1">$2</a>/x

                Was aber wenn kein Label angegeben ist?
                ich nehme s///ex (evaluiere einmal)

                m/[
                  link=
                  (
                    https?://
                    [A-Za-z0-9_.:%-]+?
                    (?:/
                      (?:[^\s#?]+?)?
                      (?:?[^\s#]+?)?
                      (?:#[^\s]+?)?
                    )?
                    (@title=.+?)?
                  ]/'<a href="'.$1.'">'. $2|| $1 . '</a>'/ex

                Wenn jetzt die url sehr lange ist, kann es sein, dass diese lange url bei fehlendem Label das layout zerstört. In diesem Falle möchte ich nur die Domain ohne Pfad etc. Die vollkommene url soll aber in ein title attribut geschrieben werden.

                Zu diesem zweck muss ich eine untergruppe speichern:
                (https?://domain)

                m/[
                  link=
                  (
                    (
                      https?://
                      [A-Za-z0-9_.:%-]+?
                    )
                    (?:/
                      (?:[^\s#?]+?)?
                      (?:?[^\s#]+?)?
                      (?:#[^\s]+?)?
                    )?
                    (@title=.+?)?
                  ]/'<a href="'.$1.'" title="'. $1 .'">'. $3 || $2 . '</a>'/ex

                So geht das in Perl. Umsetzung nach C# als Übung.
                Ich weiss nicht, ob C# die nicht speichernden (?:) versteht.
                Den Ersetzungsteil musst du sicher selbst schreiben.

                mfg Beat

                --
                Woran ich arbeite:
                X-Torah
                ><o(((°>           ><o(((°>
                   <°)))o><                     ><o(((°>o
                1. Wow. Jetzt hatte ich ernsthaft gedacht meine Lösung wäre ok, aber du belehrst mich eines besseren.

                  [...]
                  So geht das in Perl. Umsetzung nach C# als Übung.

                  Ja, das werde ich umsetzen.

                  Ich weiss nicht, ob C# die nicht speichernden (?:) versteht.

                  Das werde ich ausprobieren.

                  Ich habe das Pattern versucht anzuwenden, allerdings habe ich dann folgende Exception bekommen:

                  "[link=(https?://[A-Za-z0-9_.:%-]+?(/([^\s#?]+?)?(?[^\s#]+?)?(#[^\s]+?)?)?(@title=.+?)?]" wird analysiert - Nicht genügend )-Zeichen.

                  Es ist eine schließende Klammer zu wenig. Aber wo muss dies hin? Könntest du mir das noch sagen?

                  Bis dahin vielen Dank für deine Hilfe. Morgen werd' ich sicherlich einige Zeit darauf verwenden, diese RegEx zu verstehen. Danke schön für deine äußerst hilfreiche und ausführliche Hilfestellung.

                  Vielen Dank!

                  1. Ich habe das Pattern versucht anzuwenden, allerdings habe ich dann folgende Exception bekommen:

                    "[link=
                      (https?://
                        [A-Za-z0-9_.:%-]+?
                        (/
                          (
                            [^\s#?]+?
                          )?
                          (?
                             [^\s#]+?
                          )?
                          (#
                             [^\s]+?
                          )?
                        )?
                        (@title=.+?)?
                      )     <--- hat gefehlt
                      ]"
                    wird analysiert - Nicht genügend )-Zeichen.

                    bereinigt...

                    "[link=(https?://[A-Za-z0-9_.:%-]+?(/([^\s#?]+?)?(?[^\s#]+?)?(#[^\s]+?)?)?(@title=.+?)?)]"

                    mfg Beat

                    --
                    Woran ich arbeite:
                    X-Torah
                    ><o(((°>           ><o(((°>
                       <°)))o><                     ><o(((°>o
                    1. Nochmals vielen Dank für deine Hilfe!

                      Jetzt läuft alles durch. Morgen mache ich mich an das verstehen =)

                      Danke schön!

                    2. Hey!

                      "[link=(https?://[A-Za-z0-9_.:%-]+?(/([^\s#?]+?)?(?[^\s#]+?)?(#[^\s]+?)?)?(@title=.+?)?)]"

                      Jetzt habe ich noch eine kleine Frage/ein kleines Problem. Und zwar kann es ja sein, dass ein Anwender zwei oder mehr Links in einem Eintrag abgeben will.
                      Mein Vorgehen wäre in diesem Fall wie folgt:
                      Ich schreibe eine while-Schleife, die überprüft ob ein Link im String vorhanden ist. Anschließend soll der erste Link gesucht werden. Diesen kann ich dann auch verarbeiten. So gehe ich Schritt für Schritt durch den Text und verarbeite jeden einzelnen Link.
                      Wenn ich allerdings alle Links auf einmal suchen und ersetzen lassen will, schlägt dies fehl.

                      Als Quantifizierer würde ich "?" benützen. Aber wenn ich diesen an das Ende des Patterns stelle, dann hilft das leider nichts. Ans Ende würde ich es stellen, weil ich ja schließlich das gesamte Pattern haben will. Auch der Einsatz von Klammern hat mich nicht weitergebracht.

                      Ich möchte dass das Pattern mir immer nur einen String sucht. Könnt ihr mir da weiterhelfen?

                      Vielen Dank!
                      Ciao

  2. Für die Formatierung von Links habe ich mir das SELFForum als Vorbild genommen.
    Beispielsweise habe ich einen Link zu Google mit dem Linktext "Google": [link=http://www.google.de@title=Google].

    Schlechte Vorbilder soll man nicht nachahmen.

    Danach suche ich beliebige Wort-Zeichen (a-z, A-Z, ä, ö, ü, Ä, Ö, Ü, 0-9 und der Unterstrich). Also:
    \w

    Ich nehme an, dass eine url aus mehreren \w besteht, zudem weist sie auch den Punkt af, eventuell einen / gefolgt von mehreren \w , letztes darf sich wiederholen.

    http_url ~~~ https?://[\w.-]+(?:[/\w%?&.,;#=+-]+)?

    Zum Schluss suche ich die abschließende eckige Klammer. Also
    ]

    Das würde doch folgenden Pattern ergeben:
    [link=\w]

    warum maskierst du ] nicht ?

    Mein Code dazu sieht so aus:

    string input = "[link=http://www.google.de@title=Google]";
    link = Regex.Replace(input, @"[link=\w]", "");
    MessageBox.Show(link);

    Allerdings wird mir nur der komplette String ausgegeben. Ohne dass etwas ersetzt wurde.

    Das Wundert mich. Eigentlich sollte dein Programm-Interpreter einen Fehler melden.

    mfg Beat

    --
    Woran ich arbeite:
    X-Torah
    ><o(((°>           ><o(((°>
       <°)))o><                     ><o(((°>o
    1. Danach suche ich beliebige Wort-Zeichen (a-z, A-Z, ä, ö, ü, Ä, Ö, Ü, 0-9 und der Unterstrich). Also:
      \w

      Ich nehme an, dass eine url aus mehreren \w besteht, zudem weist sie auch den Punkt af, eventuell einen / gefolgt von mehreren \w , letztes darf sich wiederholen.

      http_url ~~~ https?://[\w.-]+(?:[/\w%?&.,;#=+-]+)?

      Ist das, ein Pattern, das zum überprüfen genutzt werden kann? (Muss man das obenstehende als Anfänger verstehen? ;-))

      Das würde doch folgenden Pattern ergeben:
      [link=\w]

      warum maskierst du ] nicht ?

      Weil mir nicht genau klar war, dass dies maskiert werden muss.

      Allerdings wird mir nur der komplette String ausgegeben. Ohne dass etwas ersetzt wurde.

      Das Wundert mich. Eigentlich sollte dein Programm-Interpreter einen Fehler melden.

      Keine Exception o.ä.

      1. gudn tach!

        Danach suche ich beliebige Wort-Zeichen (a-z, A-Z, ä, ö, ü, Ä, Ö, Ü, 0-9 und der Unterstrich). Also:
        \w

        noe, nicht unbedingt. "\w" ist locale-abhaengig. wenn man nicht weiss, was "locale-abhaengig" bedeutet, ist man auf der sicheren seite, wenn man "\w" nicht verwendet.

        Das würde doch folgenden Pattern ergeben:
        [link=\w]

        warum maskierst du ] nicht ?

        warum sollte er?

        Weil mir nicht genau klar war, dass dies maskiert werden muss.

        muss es auch gar nicht.

        Allerdings wird mir nur der komplette String ausgegeben. Ohne dass etwas ersetzt wurde.

        Das Wundert mich. Eigentlich sollte dein Programm-Interpreter einen Fehler melden.

        noe. die regexp-engines sind manchmal gar nicht so doof, wie man vermutet.

        prost
        seth