Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl Monk, Perl Meditation

qr// for problem

by Anonymous Monk
on Jun 25, 2011 at 18:57 UTC ( #911387=perlquestion: print w/replies, xml ) Need Help??
Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

Revered Monks, I come to your presence to humbly ask for enlightenment: I have this code:
$exp->expect($timeout, [ qr/.*$card,$sim.*Your Number is \+([0-9]+).*/, sub { ($gsm_number_gotten) = @{$exp->matchlist()}; print "Got gsm_number=$gsm_number_gotten for card=$card + sim=$sim\n\n"; } ]);
and it correctly grabs from the telnet connection the string ATREPLY 27,12 +CUSD: 0,"Your Number is +233266684011",15 but if I make:
my $number_string = 'Your number is \+([0-9]+)';
and then:
$exp->expect($timeout, [ qr/.*$card,$sim.*$number_string.*/, sub { ($gsm_number_gotten) = @{$exp->matchlist()}; print "Got gsm_number=$gsm_number_gotten for card=$card + sim=$sim\n\n"; } ]);
it stops grabbing the line. Could you please enlighten me to what am I doing wrong? Humbly and gratefully, Jose

Replies are listed 'Best First'.
Re: qr// for problem
by toolic (Bishop) on Jun 25, 2011 at 19:17 UTC
    my $number_string = 'Your number is \+([0-9]+)';
    my $number_string = 'Your Number is \+([0-9]+)';
    Regular expressions are case-sensitive (Number).

    I determined this by removing characters from your regex until it matched. umber is \+([0-9]+) matched, but number is \+([0-9]+) did not. Reducing code is a common debugging technique.

      Thank you so much!
Re: qr// for problem
by BrowserUk (Pope) on Jun 25, 2011 at 19:26 UTC
    Could you please enlighten me to what am I doing wrong?

    When you interpolate the string $number_string into the regex qr/.*$card,$sim.*$number_string.*/ the backslash you originally had on the '+' sign is effectively 'used up'. So by the time the regex comes to be used, that '+' will be treated as a regex meta character, specifically a quantifier modifier, for the preceding space.

    Often when interpolating a string into a regex, the way to ensure any meta-like characters within as treated as literals is to bracket the interpolated variable in \Q and \E.

    eg. qr/.*$card,$sim.*\Q$number_string\E.*/.

    But as the string actually contains meta-characters that you want recognised as such, the other option is to double the backslashes on the '+' so that one remains by the time the regex is used. Ie.

    my $number_string = 'Your number is \\+([0-9]+)'; $exp->expect($timeout, [ qr/.*$card,$sim.*$number_string.*/, ...

    Which should resolve this particular problem.

    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
      Thank you! This particular problem has a bit of twists... I get the $number_string string from a db and it will most of the times contain meta-like characters that need to taken literally but I also must grab a certain part of the matched line. So I made: my $quoted_number_string = quotemeta $number_string; then I did: $quoted_number_string =~ s/\\\@P\\\@/([0-9]+)/; (where @P@ in the original string marks the place where I must look for a sequence of digits with ([0-9]+)) and these are meta characters that must remain unescaped (so that I can store the matched sequence of digits). Then I finally do: qr/.*$card,$sim.*$quoted_number_string.*/i Now I am in doubt: should aply quotemeta twice like this?
      my $quoted_number_string = quotemeta $number_string; $quoted_number_string = quotemeta $quoted_number_string; $quoted_number_string =~ s/\\\@P\\\@/([0-9]+)/; ... qr/.*$card,$sim.*$quoted_number_string.*/i
      or this will turn each backslash into 3 backslashes instead of just 2? I am confused. Once again thank you!, you have already helped.

        Go step by step. (And, of course, understand each step.)

        AFAIU, the original source string is something like '+fo\o*@P@*b\ar+', in which all metacharacters must be metaquoted, but in which there is a '@P@' sub-string that must also be converted into an actual regex pattern. Studying and experimenting with double- and single-quoting rules will be very helpful.

        >perl -wMstrict -le "my $raw = '+fo\o*@P@*b\ar+'; print qq{'$raw'}; ;; my $mq = quotemeta $raw; print qq{'$mq'}; ;; $mq =~ s{ \\ \@ P \\ \@ }'\+([0-9]+)'xmsg; print qq{'$mq'}; ;; my $mq_rx = qr{$mq}xms; print $mq_rx; ;; my $s = '123 +fo\o*+987*b\ar+ 456'; print qq{'$s'}; $s =~ $mq_rx; print qq{'$1'}; " '+fo\o*@P@*b\ar+' '\+fo\\o\*\@P\@\*b\\ar\+' '\+fo\\o\*\+([0-9]+)\*b\\ar\+' (?msx-i:\+fo\\o\*\+([0-9]+)\*b\\ar\+) '123 +fo\o*+987*b\ar+ 456' '987'

        It's also worth remembering that while the  q{} single-quote operator doesn't interpolate, it does do a bit of escaping WRT the \ backslash character, e.g.:

        >perl -wMstrict -le "my $sq = 'start \ \\ \' stop'; print qq{'$sq'}; " 'start \ \ ' stop'

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://911387]
Approved by toolic
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others romping around the Monastery: (5)
As of 2018-06-18 02:46 GMT
Find Nodes?
    Voting Booth?
    Should cpanminus be part of the standard Perl release?

    Results (107 votes). Check out past polls.