Thilo Fester: Regex! Suche ein Wort mit Buchstaben UND Zahlen

Hey Leute,

ich bastle an einem regulären Ausdruck und finde irgendwie nicht die Lösung.

Ich möchte prüfen, ob ein Wort aus Buchstaben und Zahlen besteht.
Es dürfen weitere Zeichen enthalten sein, aber es darf beispielsweise nicht sein, dass keine Buchstaben oder keine Zahlen enthalten sind.

Mein bisheriger Lösungsansatz funktioniert leider nicht:

  
if( $wort =~ /[a-zA-Z]/g &&  $wort =~ /[0-9]/g )  
{  
  print "Ein Wort aus Buchstaben und Zahlen und vielleicht auch Sonderzeichen";  
}  

Dieser Ansatz funktioniert insbesondere dann nicht, wenn am Anfang des Wortes ein oder mehrere Zahlen stehen.

Beste Grüße
Thilo Fester

  1. Hi,

    du hast diese Seite schon entdeckt? Speziell Punkt 9 sollte interessant sein. Auch perlreref ist ganz nett.

    Gesundes Neues
      Erwin

    1. Hallo Erwin! : )
      Vielen Dank für Deine schnelle Antwort.

      du hast diese Seite schon entdeckt? Speziell Punkt 9 sollte interessant sein.

      Ja, kenne ich. ^^

      Auch perlreref ist ganz nett.

      Kannte ich noch nicht. Hilft mir aber leider auch nicht so richtig.

      Zu Punkt 9. hinterm 1. Link:
      Das gibt mir ja nur zurück, ob ich da ein Zeichen in meinem Wort habe, das entweder eine Zahl oder ein Buchstabe ist.

      Nun will ich ja aber wissen, ob definitiv beides enthalten ist. Das ist für mich ganz wichtig.
      Schön wäre dabei, wenn ich das mit nur einem Ausdruck erledigen könnte. Bisher fand ich meine Lösung ja ziemlich plausibel und sie passt eigentlich auch für alle Fälle, die ich vorher getestet hatte. Nur, wenn ich ein Wort benutze, dass mit einer Zahl beginnt, dann eben nicht.

      Es kommt mir ein bisschen vor, als würde die Suche beim zweiten Ausdruck der Bedingung nicht am Startpunkt des Wortes fortgesetzt.

  2. Hi,

    ich bastle an einem regulären Ausdruck und finde irgendwie nicht die Lösung.

    Ich möchte prüfen, ob ein Wort aus Buchstaben und Zahlen besteht.
    Es dürfen weitere Zeichen enthalten sein, aber es darf beispielsweise nicht sein, dass keine Buchstaben oder keine Zahlen enthalten sind.

    (?=[xxx]*[a-zA-Z])(?=[yyy]*[0-9])[zzz]+

    für xxx alle erlaubten Zeichen außer Buchstaben, für yyy alle erlaubten Zeichen außer Ziffern, für zzz alle erlaubten Zeichen einsetzen.

    Wenn also z.B. Ziffern, Buchstaben, Unterstrich und Bindestrich erlaubt sind:

    (?=[-0-9_]*[a-zA-Z])(?=[-a-zA-Z_]*[0-9])[-0-9a-zA-Z_]+

    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. gudn tach!

      (?=[-0-9_]*[a-zA-Z])(?=[-a-zA-Z_]*[0-9])[-0-9a-zA-Z_]+

      dieser ausdruck setzt voraus, dass der string mind. drei zeichen lang ist. das war jedoch keine vom OP genannte voraussetzung. "a4" waere nach dessen vorgaben ok, wuerde aber durch obige pruefung rasseln.

      prost
      seth

      1. gudn tach!

        (?=[-0-9_]*[a-zA-Z])(?=[-a-zA-Z_]*[0-9])[-0-9a-zA-Z_]+

        dieser ausdruck setzt voraus, dass der string mind. drei zeichen lang ist. das war jedoch keine vom OP genannte voraussetzung. "a4" waere nach dessen vorgaben ok, wuerde aber durch obige pruefung rasseln.

        prost
        seth

        Hey Seth!

        Interessanter Einwand! Das ist für mein Problem allerdings nicht wichtig, alle Worte, die ich prüfe sind mindestens 10 Zeichen lang!

      2. gudn tach!

        (?=[-0-9_]*[a-zA-Z])(?=[-a-zA-Z_]*[0-9])[-0-9a-zA-Z_]+

        dieser ausdruck setzt voraus, dass der string mind. drei zeichen lang ist. das war jedoch keine vom OP genannte voraussetzung. "a4" waere nach dessen vorgaben ok, wuerde aber durch obige pruefung rasseln.

        kaese!
        ich nehm alles zurueck!
        sorry, habe irgendwie automatisch ?: statt ?= gelesen.

        prost
        seth

      3. Hi,

        (?=[-0-9_]*[a-zA-Z])(?=[-a-zA-Z_]*[0-9])[-0-9a-zA-Z_]+

        dieser ausdruck setzt voraus, dass der string mind. drei zeichen lang ist.

        Wie kommst Du auf diese Idee?
        Der erste Lookahead guckt, ob ein Buchstabe vorhanden ist (mit oder ohne anderen erlaubten Zeichen davor),
        der zweite Lookahead guckt, ob eine Ziffer vorhanden ist (mit oder ohne anderen erlaubten Zeichen davor),
        Gematcht werden dann 1 bis unendlich viele der erlaubten Zeichen.

        Wo siehst Du hier ein "mind. 3 Zeichen"?

        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. gudn tach!

          Wie kommst Du auf diese Idee?

          bin doof.
          habe ich aber schon gesagt, bevor du antwortetest. ;-p

          [...]
          Gematcht werden dann 1 bis unendlich viele der erlaubten Zeichen.

          ja, wobei das eigentlich nicht mehr relevant fuer die abfrage ist, ob buchstaben und ziffern vorkommen.

          prost
          seth

          1. Hi,

            habe ich aber schon gesagt, bevor du antwortetest. ;-p

            Nicht bevor, sondern während.

            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. gudn tach!

              habe ich aber schon gesagt, bevor du antwortetest. ;-p

              Nicht bevor, sondern während.

              ok, genauer: ca. zwei minuten bevor du auf "nachricht absenden" klicktest.

              ach so, und s/habe/hatte/.

              prost
              seth

    2. Ich möchte prüfen, ob ein Wort aus Buchstaben und Zahlen besteht.
      Es dürfen weitere Zeichen enthalten sein, aber es darf beispielsweise nicht sein, dass keine Buchstaben oder keine Zahlen enthalten sind.

      (?=[xxx]*[a-zA-Z])(?=[yyy]*[0-9])[zzz]+

      für xxx alle erlaubten Zeichen außer Buchstaben, für yyy alle erlaubten Zeichen außer Ziffern, für zzz alle erlaubten Zeichen einsetzen.

      Wenn also z.B. Ziffern, Buchstaben, Unterstrich und Bindestrich erlaubt sind:

      (?=[-0-9_]*[a-zA-Z])(?=[-a-zA-Z_]*[0-9])[-0-9a-zA-Z_]+

      cu,
      Andreas

      Hallo Andreas!

      Ich möchte das gerne für beliebige Zeichen realisieren und habe es jetzt mit

      (?=[^a-zA-Z]*[a-zA-Z])(?=[^0-9]*[0-9]).+

      probiert. Reguläre Ausdrücke scheinen nicht meine Stärke zu sein. Es funktioniert leider nicht und ich kann mir auch nicht erklären wieso.

      Anbei noch eine Frage zum Verständnis: (?= ... ) ist eine Bedingung die auf das komplette Wort geprüft wird und das Ergebnis muss wahr sein um den Rest des Ausdrucks auch auszuwerten, richtig?

      Besten Dank für Deine Hilfe!
      Thilo

      1. Hi,

        (?=[^a-zA-Z]*[a-zA-Z])(?=[^0-9]*[0-9]).+

        probiert.

        Und das funktioniert. Das matcht Strings, die mind. 1 Buchstaben und mind. 1 Ziffer enthalten.

        Anbei noch eine Frage zum Verständnis: (?= ... ) ist eine Bedingung die auf das komplette Wort geprüft wird und das Ergebnis muss wahr sein um den Rest des Ausdrucks auch auszuwerten, richtig?

        (?= ... ) ist ein positive Lookahead.
        Der gibt genau dann true, wenn an der entsprechenden Position der Inhalt der Klammer matcht.

        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.
      2. gudn tach!

        Ich möchte das gerne für beliebige Zeichen realisieren und habe es jetzt mit

        (?=[^a-zA-Z]*[a-zA-Z])(?=[^0-9]*[0-9]).+

        probiert. Reguläre Ausdrücke scheinen nicht meine Stärke zu sein. Es funktioniert leider nicht und ich kann mir auch nicht erklären wieso.

        /(?=[^a-zA-Z]*[a-zA-Z])(?=[^0-9]*[0-9]).+/

        matcht das gleiche wie

        /(?=[^a-zA-Z]*[a-zA-Z])(?=[^0-9]*[0-9])/

        also eine stelle, nach der sowohl
          /[^a-zA-Z]*[a-zA-Z]/
        als auch
          /[^0-9]*[0-9]/
        matcht.

        sollte also funzen.

        im code kuerzer wird's uebrigens mit

        /(?=[^a-z]*[a-z])(?=\D*\d)/i

        (?= ... ) ist eine Bedingung die auf das komplette Wort geprüft wird und das Ergebnis muss wahr sein um den Rest des Ausdrucks auch auszuwerten, richtig?

        nee, sowas gibt es zwar auch. aber das hier ist eine zero-width positive look-ahead assertion. siehe "perldoc perlre".

        prost
        seth

  3. gudn tach!

    es darf [...] nicht sein, dass keine Buchstaben oder keine Zahlen enthalten sind.

    if( $wort =~ /[a-zA-Z]/g && $wort =~ /[0-9]/g )

    fast. lass die einfach die 'g's weg.

    Dieser Ansatz funktioniert insbesondere dann nicht, wenn am Anfang des Wortes ein oder mehrere Zahlen stehen.

    genau, und zwar wegen dem g-modifier. der verhindert, dass der regexp-"zeiger" nach der suche zurueckgesetzt wird; siehe http://perldoc.perl.org/perlretut.html#Using-regular-expressions-in-Perl fuer genaueres.

    wenn's _ein_ ausdruck sein soll, koenntest du's auch mit
      /[a-z].*\d|\d.*[a-z]/i
    loesen.

    prost
    seth

    1. fast. lass die einfach die 'g's weg.

      Bestens! Das Problem ist jetzt zumindest erstmal gelöst! : )
      Vielen Dank!

      wenn's _ein_ ausdruck sein soll, koenntest du's auch mit
        /[a-z].*\d|\d.*[a-z]/i
      loesen.

      Also ich habe das einfach einmal getestet. Die Lösung mit einem einzigen regulären Ausdruck ist natürlich um einiges eleganter als meine jetzige.
      Deine RegEx trifft allerdings einiges und auch Worte, die keine Zahlen und keine Buchstaben enthalten.

      ~ Thilo

      1. gudn tach!

        wenn's _ein_ ausdruck sein soll, koenntest du's auch mit
          /[a-z].*\d|\d.*[a-z]/i
        loesen.

        Deine RegEx trifft allerdings einiges und auch Worte, die keine Zahlen und keine Buchstaben enthalten.

        z.b.?

        prost
        seth

        1. Deine RegEx trifft allerdings einiges und auch Worte, die keine Zahlen und keine Buchstaben enthalten.

          z.b.?

          abcdefghijk

          ~ Thilo

          1. gudn tach!

            Deine RegEx trifft allerdings einiges und auch Worte, die keine Zahlen und keine Buchstaben enthalten.

            z.b.?

            abcdefghijk

            also wenn ich im cli den code

            perl -e '$wort="abcdefghij"; print "kein " if($wort !~ /\d.*[a-z]|[a-z].*\d/i); print "match\n"'

            ausfuehre, erscheint "kein match" (weil keine ziffer vorkommt). so wolltest du es doch, oder nicht?

            bei dir waere es im code dann

            if($wort =~ /\d.*[a-z]|[a-z].*\d/i){  
              print "Ein Wort aus Buchstaben und Zahlen und vielleicht auch Sonderzeichen";  
            }
            

            prost
            seth

            1.   
              if( !$data{'passwort'} =~ /[a-z].*\d|\d.*[a-z]/i )  
              {  
                print qq~  
                 Kein Treffer  
                ~;  
              }  
              
              

              Gibt bei mir "Kein Treffer" für abcedefghijk...

              Hab soeben aber gemerkt, dass

                
              if( $data{'passwort'} !~ /[a-z].*\d|\d.*[a-z]/i )  
              {  
                print qq~  
                 Kein Treffer  
                ~;  
              }  
              
              

              ... hingegen so funktioniert, wie ich das gern möchte.

              Hm.

              ~ Thilo

              1. Hi

                if( !$data{'passwort'} =~ /[a-z].\d|\d.[a-z]/i )
                {
                  print qq~
                   Kein Treffer
                  ~;
                }

                
                >   
                > Gibt bei mir "Kein Treffer" für abcedefghijk...  
                >   
                > Hab soeben aber gemerkt, dass  
                >   
                > ~~~perl
                  
                
                > if( $data{'passwort'} !~ /[a-z].*\d|\d.*[a-z]/i )  
                > {  
                >   print qq~  
                >    Kein Treffer  
                >   ~;  
                > }  
                > 
                
                

                ... hingegen so funktioniert, wie ich das gern möchte.

                Hm.

                interessant gell? Versuche mal "not" statt ! oder Klammer den Ausdruck vorm negieren oder benutze "unless" statt "if":

                #~~~perl

                $="\n"; # print mit newline

                $data='abcedefghijk';

                if( ! $data =~ /[a-z].\d|\d.[a-z]/i )
                 { print "Match ! =~";}

                if( not $data =~ /[a-z].\d|\d.[a-z]/i )
                 { print "Match not =~";}

                if( ! ($data =~ /[a-z].\d|\d.[a-z]/i) )
                 { print "Match !( =~ )";}

                unless( $data =~ /[a-z].\d|\d.[a-z]/i )
                 { print "Match unless( =~ )";}

                if( ! $data == "" )
                 { print "Match !$data==Leerstring";}

                  
                  
                Bei deiner Schreibweise wird $data erst negiert und damit zum Leerstring.  
                  
                "!" hat eine verdammt hohe Operatorprezedenz, höher als =~ ...  
                deswegen lieber "not" nehmen.  
                  
                Oder noch besser die Lösung mit den zwo einfachen RegExes die mit && verknüpft werden:  
                  
                ~~~perl
                  
                print 'ziffer und buchstaben vorhanden' if ( $str=~/[a-z]/i && $str=~/\d/ );  
                
                

                Die ist nämlich sofort lesbar, nach längerer Zeit sofort verständlich und damit WARTBAR. (Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live. -- Damian Conway in "Perl Best Practices")

                Alle anderen Regexes bei deiner Fragestellung sind IMHO letztendlich intellektuelle Masturbation und höchstens bei sehr zeitkritischen Anwendungen sinnvoll.

                Gruß
                 Kurt

  4. gudn tach!

    ich fasse mal in diesem posting die loesungen von MudGuard und mir zusammen, weil der gesamtthread doch etwas unuebersichtlich geworden ist.

    um zu testen, ob ein string $str mind. einen lateinischen buchstaben und mind. eine ziffer enthaelt, kann man z.b. folgende verschiedenen regexps verwenden:

    print 'ziffer und buchstaben vorhanden' if $str=~/(?=[^a-z]*[a-z])(?=\D*\d)/i;  
    print 'ziffer und buchstaben vorhanden' if $str=~/[a-z].*\d|\d.*[a-z]/i;  
    print 'ziffer und buchstaben vorhanden' if $str=~/[a-z]/i && $str=~/\d/;
    

    oder negiert (die negation laesst sich an verschiedenen stellen anwenden):

      
    print 'ziffer oder buchstaben nicht vorhanden' if   $str!~/(?=[^a-z]*[a-z])(?=\D*\d)/i;  
    print 'ziffer oder buchstaben nicht vorhanden' if !($str=~/(?=[^a-z]*[a-z])(?=\D*\d)/i);  
    # ohne klammern, waer's falsch, weil "!" staerker bindet. also falsch: if !$str=~/(?=[^a-z]*[a-z])(?=\D*\d)/i;  
    print 'ziffer oder buchstaben nicht vorhanden' if   $str!~/[a-z].*\d|\d.*[a-z]/i;  
    print 'ziffer oder buchstaben nicht vorhanden' if !($str=~/[a-z].*\d|\d.*[a-z]/i);  
    print 'ziffer oder buchstaben nicht vorhanden' if !($str=~/[a-z]/i     && $str!~/\d/);  
    print 'ziffer oder buchstaben nicht vorhanden' if   $str!~/[a-z]/i     || $str!~/\d/;  
    print 'ziffer oder buchstaben nicht vorhanden' if   $str=~/^[^a-z]*$/i || $str=~/^\D*$/;
    

    prost
    seth