Ralf: regexp gesucht

Hallo,

ich möchte aus einer Url den Dateinamen ohne Endung extrahieren. Also den Teil nach dem letzten "/" und vor dem letzten ".". Außerdem soll bei dem Dateinamen ein evtl. vorhandener Suffix, welcher mit "_" beginnt und 3 Ziffern hat, wegfallen.

Beispiele:
http://www.domain.de/abc/xyz/dateiname.jpg ==> dateiname
http://www.domain.de/abc/xyz/dateiname_123.jpg ==> dateiname
http://www.domain.de/abc/xyz/dateiname123.jpg ==> dateiname123
http://www.domain.de/abc/xyz/dateiname_123_abc.jpg ==> dateiname_123_abc

Mit mehreren Abfragen nacheinander ist das kein Problem, aber bekommt man das auch mit einer einzigen hin?

Ralf

  1. ich möchte aus einer Url den Dateinamen ohne Endung extrahieren. Also den Teil nach dem letzten "/" und vor dem letzten ".". Außerdem soll bei dem Dateinamen ein evtl. vorhandener Suffix, welcher mit "_" beginnt und 3 Ziffern hat, wegfallen.

    RegExp: /^.+/(.+?(_|.))/
    RegExp.$1 enthält das gesuchte.

    JJ

    1. ich möchte aus einer Url den Dateinamen ohne Endung extrahieren. Also den Teil nach dem letzten "/" und vor dem letzten ".". Außerdem soll bei dem Dateinamen ein evtl. vorhandener Suffix, welcher mit "_" beginnt und 3 Ziffern hat, wegfallen.
      RegExp: /^.+/(.+?(_|.))/
      RegExp.$1 enthält das gesuchte.

      Vielen Dank für die schnelle Antwort. Aber leider führt das nicht zum gewünschten Ergebnis. Ich habe es ausprobiert und es wird immer der gesamte Dateiname inkl. Endung geliefert.

      1. RegExp: /^.+/(.+?(_|.))/
        RegExp.$1 enthält das gesuchte.
        Aber leider führt das nicht zum gewünschten Ergebnis. Ich habe es ausprobiert und es wird immer der gesamte Dateiname inkl. Endung geliefert.

        Dann machst du was flasch (abgesehen davon, dass meine Klammerung nicht korrekt war, da die den Punkt bzw. den Unterstrich mit einfängt, was du aber sicher nicht willst):

        var re = /^.+/(.+)?(_|.)/;
        var st = 'http://www.example.de/user/foobar.jpg';
        if(re.test(st))
          alert(RegExp.$1) // foobar

        JJ

        1. Dann machst du was flasch (abgesehen davon, dass meine Klammerung nicht korrekt war, da die den Punkt bzw. den Unterstrich mit einfängt, was du aber sicher nicht willst):

          var re = /^.+/(.+)?(_|.)/;
          var st = 'http://www.example.de/user/foobar.jpg';
          if(re.test(st))
            alert(RegExp.$1) // foobar

          Und foobar_123.jpg wird zu foobar_123 - soll aber ebenfalls zu foobar werden ...

          Ralf

          1. Und foobar_123.jpg wird zu foobar_123 - soll aber ebenfalls zu foobar werden ...

            Ahja, mißverstanden. Dann eben so:

            var re = /^.+/(.+)?(_[0-9[{3}.|.)/;

            Besser?

            JJ

            1. var re = /^.+/(.+)?(_[0-9[{3}.|.)/;

              var re = /^.+/(.+)?(_[0-9]{3}.|.)/;

              Klammer verdreht, sry

              1. Klammer verdreht, sry

                Hatte ich bemerkt ...

            2. var re = /^.+/(.+)?(_[0-9[{3}.|.)/;

              Besser?

              Nein - foobar_123. Es wird offensichtlich immer die weniger restriktive Definition genommen.

              Ralf

              1. Besser?
                Nein - foobar_123. Es wird offensichtlich immer die weniger restriktive Definition genommen.

                Nu mal langsam. Die URL's aus deinem Eröffnungsposting:

                http://www.domain.de/abc/xyz/dateiname.jpg
                http://www.domain.de/abc/xyz/dateiname_123.jpg
                http://www.domain.de/abc/xyz/dateiname123.jpg
                http://www.domain.de/abc/xyz/dateiname_123_abc.jpg

                ergeben genau das, was du an Anforderungen beschrieben hast, nämlich dateiname, dateiname, dateiname123 und dateiname_123_abc. Das Korrekturposting hattest du gesehen, da war eine Klammer falsch rum.

                JJ

                1. Nu mal langsam. Die URL's aus deinem Eröffnungsposting:

                  http://www.domain.de/abc/xyz/dateiname.jpg
                  http://www.domain.de/abc/xyz/dateiname_123.jpg
                  http://www.domain.de/abc/xyz/dateiname123.jpg
                  http://www.domain.de/abc/xyz/dateiname_123_abc.jpg

                  ergeben genau das, was du an Anforderungen beschrieben hast, nämlich dateiname, dateiname, dateiname123 und dateiname_123_abc.

                  Eben nicht. Ich habe es ausprobiert. Ist jetzt aber auch egal, da die Lösung gefunden wurde.

                  Trotzdem vielen Dank für deinen Bemühungen.

                  Ralf

                  1. Nu mal langsam. Die URL's aus deinem Eröffnungsposting:

                    http://www.domain.de/abc/xyz/dateiname.jpg
                    http://www.domain.de/abc/xyz/dateiname_123.jpg
                    http://www.domain.de/abc/xyz/dateiname123.jpg
                    http://www.domain.de/abc/xyz/dateiname_123_abc.jpg

                    ergeben genau das, was du an Anforderungen beschrieben hast, nämlich dateiname, dateiname, dateiname123 und dateiname_123_abc.
                    Eben nicht. Ich habe es ausprobiert.

                    Ist eben nicht egal! Der RegExp wie er da steht tut genau das, was du als Anforderungen beschrieben hast. Also muß es einen Grund geben, daß er bei mir funzt, bei dir aber nicht.

                    JJ

                    1. Ist eben nicht egal! Der RegExp wie er da steht tut genau das, was du als Anforderungen beschrieben hast. Also muß es einen Grund geben, daß er bei mir funzt, bei dir aber nicht.

                      Ich weiß nicht, was du getestet hast. Bei mir:

                      var re = /^.+/(.+)?(_[0-9]{3}.|.)/;
                      var st = 'http://www.example.de/user/foobar_123.jpg';
                      if(re.test(st))
                        alert(RegExp.$1) // foobar_123

                      Ralf

                      1. var re = /^.+/(.+)?(_[0-9]{3}.|.)/;

                        Mann, ich Vollpfosten! Mein RE sieht so aus:
                        /^.+/(.+?)(_[0-9]{3}.|.)/

                        Kleiner aber feiner Unterschied ;-)

                        JJ

                        1. Kleiner aber feiner Unterschied ;-)

                          Stimmt. Und dank Gunnars Erläuterungen verstehe ich den sogar ^^

                          Ralf

  2. ich möchte aus einer Url den Dateinamen ohne Endung extrahieren. Also den Teil nach dem letzten "/" und vor dem letzten ".". Außerdem soll bei dem Dateinamen ein evtl. vorhandener Suffix, welcher mit "_" beginnt und 3 Ziffern hat, wegfallen.

    Beispiele:
    http://www.domain.de/abc/xyz/dateiname.jpg ==> dateiname
    http://www.domain.de/abc/xyz/dateiname_123.jpg ==> dateiname
    http://www.domain.de/abc/xyz/dateiname123.jpg ==> dateiname123
    http://www.domain.de/abc/xyz/dateiname_123_abc.jpg ==> dateiname_123_abc

    Das klingt unlogisch, warum muss das so sein?
    In JS wirst du das mit einem Regulären Ausdruck nicht hinkriegen, da es dort kein lookbehind gibt.

    Struppi.

    1. Das klingt unlogisch, warum muss das so sein?

      Vielleicht habe ich es nicht richtig ausgedrückt. Mich interessiert der Dateiname (ohne Endung). Wenn er aber einen numerischen Suffix nach einem Unterstrich enthält, soll dieser Suffix inkl. Unterstrich weggelassen werden.
      Hintergrund ist, dass das Ergebnis als class Attribut zugeordnet werden soll, ein evtl. vorhandener Suffix aber die Eindeutigkeit verhindert.

      In JS wirst du das mit einem Regulären Ausdruck nicht hinkriegen, da es dort kein lookbehind gibt.

      Könnte es nicht gehen, wenn die Dateiendung und Suffix inkl. Endung als alternative Beendigungen der RegExp definiert werden?

      Ralf

      1. Das klingt unlogisch, warum muss das so sein?
        Vielleicht habe ich es nicht richtig ausgedrückt. Mich interessiert der Dateiname (ohne Endung). Wenn er aber einen numerischen Suffix nach einem Unterstrich enthält, soll dieser Suffix inkl. Unterstrich weggelassen werden.
        Hintergrund ist, dass das Ergebnis als class Attribut zugeordnet werden soll, ein evtl. vorhandener Suffix aber die Eindeutigkeit verhindert.

        Wenn ich dich richtig verstehe gehören die beiden zusammen:
        dateiname.jpg ==> dateiname
        dateiname_123.jpg ==> dateiname

        aber das gehört nicht dazu:
        dateiname_123_abc.jpg ==> dateiname_123_abc

        das erscheint mir unlogisch

        In JS wirst du das mit einem Regulären Ausdruck nicht hinkriegen, da es dort kein lookbehind gibt.
        Könnte es nicht gehen, wenn die Dateiendung und Suffix inkl. Endung als alternative Beendigungen der RegExp definiert werden?

        Das Problem ist doch, wenn du nach _xxx (x = Zahl) suchst und ersetzen willst, musst du gleichzeitig schauen, ob danach noch ein _cccc ( c = zeichen ) kommt. also du musst vorher Wissen, was nachher noch folgen wird. Das ist ein lookbehind.

        Struppi.

        1. Wenn ich dich richtig verstehe gehören die beiden zusammen:
          dateiname.jpg ==> dateiname
          dateiname_123.jpg ==> dateiname

          Richtig. Dies soll darstellen, dass der Suffix ignoriert werden soll.

          aber das gehört nicht dazu:
          dateiname_123_abc.jpg ==> dateiname_123_abc

          Doch. Das soll darstellen, dass so eine Kombination innerhalb des Dateinamens gültig ist und im Ergebnis erscheinen soll. Allerdings habe ich so einen Fall praktisch nicht. Es können aber im Dateinamen durchaus mehrere Unterstriche auftauchen und es soll dann nur besagter Suffix entfallen.

          Das Problem ist doch, wenn du nach _xxx (x = Zahl) suchst und ersetzen willst, musst du gleichzeitig schauen, ob danach noch ein _cccc ( c = zeichen ) kommt. also du musst vorher Wissen, was nachher noch folgen wird. Das ist ein lookbehind.

          Ok. Dann können wir alles nach _xxx (x = Zahl) ignorieren. Geht es dann?

          Ralf

          1. Wenn ich dich richtig verstehe gehören die beiden zusammen:
            dateiname.jpg ==> dateiname
            dateiname_123.jpg ==> dateiname

            Richtig. Dies soll darstellen, dass der Suffix ignoriert werden soll.

            aber das gehört nicht dazu:
            dateiname_123_abc.jpg ==> dateiname_123_abc

            Doch. Das soll darstellen, dass so eine Kombination innerhalb des Dateinamens gültig ist und im Ergebnis erscheinen soll. Allerdings habe ich so einen Fall praktisch nicht. Es können aber im Dateinamen durchaus mehrere Unterstriche auftauchen und es soll dann nur besagter Suffix entfallen.

            Das ist die grosse Frage, es gbt soclhe Dateinamen:
            dateiname.jpg
            dateiname_123.jpg
            dateiname_abc_123.jpg
            dateiname_abc_def_123.jpg

            du willst also .jpg und ein vorher evtl. vorhandenes _\d\d\d entfernen?

            Ok. Dann können wir alles nach _xxx (x = Zahl) ignorieren. Geht es dann?

            klar.

            Struppi.

            1. du willst also .jpg und ein vorher evtl. vorhandenes _\d\d\d entfernen?

              Genau. Kann aber auch .gif, .png etc. sein.

              Ok. Dann können wir alles nach _xxx (x = Zahl) ignorieren. Geht es dann?

              klar.

              Verrätst du es mir?

              Ralf

  3. @@Ralf:

    ich möchte aus einer Url den Dateinamen ohne Endung extrahieren. Also den Teil nach dem letzten "/" und vor dem letzten ".". Außerdem soll bei dem Dateinamen ein evtl. vorhandener Suffix, welcher mit "_" beginnt und 3 Ziffern hat, wegfallen.

    Dann werfe ich mal den in die Runde: .*/(.*?)(?:_\d{3})?.[^.]*

    .*/ sollte gierig alles bis zum letzten '/' matchen

    (.*?) den Dateinamen; ? – nicht gierig; () – merken

    (?:_\d{3})? matcht '_' und 3 Ziffern; (?: – nicht merken, ? an Ende – kann einman vorkommen, muss aber nicht

    .[^.]* letzter '.' und danachfolgende Zeichen

    Dass '/' in JavaScript maskiert werden muss, wenn das Zeichen als Delimiter dient, sollte klar sein.

    Live long and prosper,
    Gunnar

    --
    „Das Internet ist ein großer Misthaufen, in dem man allerdings auch kleine Schätze und Perlen finden kann.“ (Joseph Weizenbaum)
    1. Dann werfe ich mal den in die Runde: .*/(.*?)(?:_\d{3})?.[^.]*

      Absolut perfekt! Damit kann sogar _\d\d\d innerhalb des Namens auftauchen.

      .*/ sollte gierig alles bis zum letzten '/' matchen

      (.*?) den Dateinamen; ? – nicht gierig; () – merken

      (?:_\d{3})? matcht '_' und 3 Ziffern; (?: – nicht merken, ? an Ende – kann einman vorkommen, muss aber nicht

      .[^.]* letzter '.' und danachfolgende Zeichen

      Und vielen Dank für die super Erklärung!

      Ralf

    2. gudn tach!

      Dann werfe ich mal den in die Runde: .*/(.*?)(?:_\d{3})?.[^.]*

      .*/ sollte gierig alles bis zum letzten '/' matchen

      macht es auch, zunaechst. aber falls der kram danach nicht matcht, wird zum vorletzten slash gesprungen, usw.

      deswegen wuerde bspw. bei
        "http://www.domain.de/abc/xyz/dateiname"
      der string
        "www"
      zurueckgeliefert, was nicht unbedingt gewollt ist. (kann natuerlich auch sein, dass sowas gar nicht vorkommt, dann waer's eh egal.)

      .[^.]* letzter '.' und danachfolgende Zeichen

      [^.]* matcht immer, kann also auch einfach weggelassen werden. oder man verlangt, dass danach der string zuende ist.

      ich schlage deshalb etwas restriktiveres vor wie z.b.
        ~.*/(.*?)(?:_\d{3})?.\w+\z~
      oder
        ~([^/.]*?)(?:_\d{3})?.\w+\z~

      prost
      seth

      1. Hallo,

        .[^.]* letzter '.' und danachfolgende Zeichen

        [^.]* matcht immer, kann also auch einfach weggelassen werden.

        Nein, das matcht nur bis zum nächsten Punkt. Ein Dateiname kann mehrere Punkte enthalten, z.B. "Datei.abcyxz.doc.pdf.gif.pl". Dass meistens nur ein Punkt benutzt wird, ist ein mir ziemlich unverständliches ungeschriebenes Gesetz.

        Gruß, Don P

        1. gudn tach!

          .[^.]* letzter '.' und danachfolgende Zeichen

          [^.]* matcht immer, kann also auch einfach weggelassen werden.

          Nein

          na, dann gib mir mal einen string, bei dem das pattern immer matcht.

          iow: doch!

          , das matcht nur bis zum nächsten Punkt.

          genau genommen nein. das ende eines strings ist z.b. kein punkt. ist aber fuer meine aussage
            "[^.]* matcht immer"
          voellig egal, denn [^.]* matcht immer. sogar im string "..." wird der leere string gematcht:
          perl -e '$_="..."; print "baetsch!\n" if /.[^.]*/;'

          [^.]* als regexp-ende macht beim matchen keinen sinn, wenn man darauf spaeter nicht mehr zugreift (vgl. auch OP).

          prost
          seth

          1. gudn tach!

            ahrg, verschrieben.

            [^.]* matcht immer, kann also auch einfach weggelassen werden.

            Nein

            <s>na, dann gib mir mal einen string, bei dem das pattern immer matcht.</s>

            korrektur:
            na, dann gib mir mal einen string, bei dem das pattern _nicht_ matcht.

            iow: doch!

            ab da stimmt's wieder. ;-)

            prost
            seth

          2. Hallo,

            [^.]* als regexp-ende macht beim matchen keinen sinn, wenn man darauf spaeter nicht mehr zugreift (vgl. auch OP).

            Äh, ja, so gesehen stimmt das natürlich. Dachte, dass du nach dem Punkt ohnehin keine weiteren Punkte mehr erwartest und deshalb "matcht immer" schriebst.

            [^.]* als regexp-Ende ohne weiteren Zugriff darauf macht so viel oder so wenig Sinn wie .* oder .? als regexp-Ende, ist schon klar.

            Gruß, Don P

      2. macht es auch, zunaechst. aber falls der kram danach nicht matcht, wird zum vorletzten slash gesprungen, usw.

        deswegen wuerde bspw. bei
          "http://www.domain.de/abc/xyz/dateiname"
        der string
          "www"
        zurueckgeliefert, was nicht unbedingt gewollt ist. (kann natuerlich auch sein, dass sowas gar nicht vorkommt, dann waer's eh egal.)

        Kommt für die praktische Anwendung nicht vor.

        ich schlage deshalb etwas restriktiveres vor wie z.b.
          ~.*/(.*?)(?:_\d{3})?.\w+\z~
        oder
          ~([^/.]*?)(?:_\d{3})?.\w+\z~

        Für mich zur Information, weil ich es nicht gefunden habe - wofür steht \z ?

        Ralf

        1. Hallo Ralf!

          ich schlage deshalb etwas restriktiveres vor wie z.b.
            ~.*/(.*?)(?:_\d{3})?.\w+\z~
          oder
            ~([^/.]*?)(?:_\d{3})?.\w+\z~

          matcht bei »mysupersong.mp3« aber net, äääätsch ;)

          Für mich zur Information, weil ich es nicht gefunden habe - wofür steht \z ?

          Für das Ende des Alphabets... und für's Stringende... ;)

          Viele Grüße aus Frankfurt/Main,
          Patrick

          --

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

            matcht bei »mysupersong.mp3« aber net, äääätsch ;)

            Ups, doch - hatte mein kopf wo anders, sorry.

            Viele Grüße aus Frankfurt/Main,
            Patrick

            --

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

          ich schlage deshalb etwas restriktiveres vor wie z.b.
            ~.*/(.*?)(?:_\d{3})?.\w+\z~
          oder
            ~([^/.]*?)(?:_\d{3})?.\w+\z~

          Für mich zur Information, weil ich es nicht gefunden habe - wofür steht \z ?

          \z matcht das ende eines strings. im gegensatz zu $ wird kein etwaiges newline gematcht.
          eine gutes regexp-manual ist uebrigens perldoc perlre.

          prost
          seth