natxo has asked for the wisdom of the Perl Monks concerning the following question:

hi, I need to match a series of wonderfully vague MS ldap errors in order to present some decent information to my users. The kind of errors I get is like this:
00000056: AtrErr: DSID-03190F80, #1: 0: 00000056: DSID-03190F80, problem 1005 (CONSTRAINT_ATT_TYPE), da +ta 0, Att 9005a (unicodePwd)
Anyway, I created a hash (incomplete, but just to get the idea) with the translations to normal language: So I want to match the key to the error, and I came up with this, but it never matches:

Edit: I updated the question with a piece of code. The $error comes from the actual error method in Net::LDAP and if I add [] to print it it actually looks like this:

[00000056: AtrErr: DSID-03190F80, #1: 0: 00000056: DSID-03190F80, problem 1005 (CONSTRAINT_ATT_TYPE), da +ta 0, Att 9005a (unicodePwd) ]
with the last ']' as only character in the line.
$error = "00000056: AtrErr: DSID-03190F80, #1: 0: 00000056: DSID-03190F80, problem 1005 (CONSTRAINT_ATT_TYPE), da +ta 0, Att 9005a (unicodePwd) "; my %pwd_reset_errors = ( '0000052D' => "new password does not meet complexity requirements" +, '00000056' => "wrong old password", ); while ( my ( $key, $value ) = each %pwd_reset_errors ) { if ( $key =~ m/^$error.*/ ) { app->log->debug("$value"); } }
But it is obviously not working. What is wrong with my crappy regular expression? :-) Thanks in advance

Replies are listed 'Best First'.
Re: regex match multiple line
by ww (Archbishop) on Nov 26, 2014 at 22:06 UTC
    The first thing that leaps at /me is the inappropriate escaping of the sigil in the regex. The next is that you ask would-be helpers to take at face value -- that is, without code to back up the claim -- that "(you) created a hash...." ... which, for the limited purpose of this WAG, I'll take for fact, since it's a plausible sample of a hash.

    But the next big ugly is is that you haven't given us enough with which to confidently jump off a cliff.

    ... but here goes anyway (sure hope the water's deep down there) (code and output updated for clarity):

    use strict; use warnings; use 5.018; # 1108508 my $error = qr/00000056|0000052D|05601111/; my %pwd_reset_errors = ( '0000052D' => "new password does not meet complexity requirements" +, '00000056' => "wrong old password", '05601111' => "Friends don't let friends use Doze", '123xx51y' => "Not a Windows error (or undocumented)", ); while ( my ( $key, $value ) = each %pwd_reset_errors ) { if ( $key =~ m/^$error.*/ ) { # Don't esca +pe the sigil here! say "matched \$key: $key in \$error: \r\n\t \$value: $value\n"; } else { say "Didn't find a match for $key [ $value ]) in regex $error\n" +; } }

    Execution:

    C:\>1108508.pl Didn't find a match for 123xx51y [ Not a Windows error (or undocumente +d) ]) in regex (?^u:00000056|0000052D|05601111) matched $key: 00000056 in $error: $value: wrong old password matched $key: 0000052D in $error: $value: new password does not meet complexity requirements matched $key: 05601111 in $error: $value: Friends don't let friends use Doze

    Note the use of qr in the declaration of the string you're trying to use (I think -- sorry, Xtal ball is gebroke!) as a regex... and, of course, the use of strict, warnings, etc.

    ...and that the irony in the messages IS intentional. :-)

    ++$anecdote ne $data


      Thanks! I get the irony ;-)

      In fact the $error is not the regex I want to match, but the other way round. I want to match the key of my hash as a regex to the error I get from Net::LDAP.

      I apologize for the confusion.

        In case you haven't figured it out yet, you're really close. In your while loop, change this:
        if ( $key =~ m/^$error.*/ ) {
        to this:
        if ( $error =~ m/^$key:/ ) {
        Then again, maybe I totally misunderstood your question.
        while ( my ( $key, $value ) = each %pwd_reset_errors ) { if ( $key =~ m/^$error.*/ ) { ... }
        This iterates thru the hash list %pwd_reset_errors right? So whats wrong with doing it like this above IF the key matches the error code? Why would you want to match it the other way around? I am just asking for better understanding :)

        To me its like you wanting to do soemthing of this nature:
        my $one = 1; if ($one =~ 1){ ... }elsif(1 =~ $one){ ... }
        Why would it matter if $one eq 1 or 1 eq $one, they were both the same thing. But like i said i am just asking for better understanding.


        EDIT: I just realized that Net::LDAP error is quite different than your keys in the hash. You could split the error code from Net::LDAP so it just contains everything before ':' and then match either way.

        EDIT 2: I had to much coffee. ;l
Re: regex match multiple line (updated question)
by Laurent_R (Canon) on Nov 27, 2014 at 07:19 UTC
    I don't really understand what you are trying to do, but the one thing that came to my mind is that is you have this:
    [00000056: AtrErr: DSID-03190F80, #1: 0: 00000056: DSID-03190F80, problem 1005 (CONSTRAINT_ATT_TYPE), da +ta 0, Att 9005a (unicodePwd) ]
    then you are probably missing a chomp when processing your data.
Re: regex match multiple line (updated question)
by wazat (Monk) on Nov 27, 2014 at 18:15 UTC

    I'm not sure why you are approaching the problem this way. Am I missing something, or can't you just grab the error code from the error string, then do a lookup in your hash? For example:

    $error = "00000056: AtrErr: DSID-03190F80, #1: 0: 00000056: DSID-03190F80, problem 1005 (CONSTRAINT_ATT_TYPE), da +ta 0, Att 9005a (unicodePwd) "; my %pwd_reset_errors = ( '0000052D' => "new password does not meet complexity requirements" +, '00000056' => "wrong old password", ); my($error_code) = ($error =~ m/(\d+):/); print $pwd_reset_errors{$error_code}, "\n";

    This prints

    wrong old password