Search code examples
regexperl

Not returning matched regex character in perl


Trying to teach myself perl and regexes.

Would like to know how to return the "+" if a user enters Smith+ in lastname. As in, "User entered invalid character, specifically "+" in the last name field."

unless (    $string1 =~ m/^[\w\.\s\-]+$/        &&  #last name must contain only words, periods, spaces and dashes
            $string2 =~ m/^[\w\.\s\-\@]+$/      &&  #email must contain only words, periods, spaces and dashes and at symbols
            $string3 eq "Find Order"            &&  #submit button field must match Find Order
            $string1 ne ''                      &&  #last name can't be empty
            $string2 ne ''                          #email can't be empty
       )
       {
       print "$& $1 $` $'";    #these don't return anything and it makes me sad
       &error;
       }

Solution

  • One way would be to explicitly test for bad characters and/or conditions

    if ( $string1 eq '' ) { 
        say "Name can't be empty";
        error();
    }
    elsif ( my @bad_namechars = $string1 =~ /([^\w.\s-])/g ) { 
        say "Character(s) \"@bad_chars\" aren't expected in a name";
        error();
    }
    elsif ( $string2 eq '' ) { ... }
    elsif ( my @bad_emailchars =~ /([^\w.\s-\@])/g ) { ... } # etc
    

    If you'd rather detect all errors, so to inform the user, then make these independent if statements and perhaps set a flag in each, so to then be able to invoke error() once after all tests, if any error(s) occurred.

    While these tests can be organized in other ways, having one composite test with multiple regexes cannot really fill the stated need. Each new regex resets most of internal variables, and at any rate one couldn't tell which regex (mis)matched so error reporting wouldn't work.

    One can make this work by stringing expressions that assign captures like above but that would lead to code that's easy to advise against--and, since Perl's && (and and, etc) operators short-circuit, one could only detect one error that way.

    I assume that &error refers to a custom sub; if so, then that & is probably not needed.


    This still can only catch one (first tested) error since or short-circuits

    if ( 
        (my $empty_name = $string1 eq '')        or
        (my @bad_namechars = $string1 =~ /.../)  or
        ... 
    ) { ... }