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

given the string:
$str = "this %%q is my %q string"

I can match the "%q" with the following:
$str = s/\%q//g;

but this also matches the "%%q", how do i need to modify this pattern match to not match %%q?

Replies are listed 'Best First'.
Re: regex match question
by liz (Monsignor) on Aug 03, 2003 at 16:57 UTC
    From perlre:
    "(?<=pattern)"
                     A zero-width positive look-behind assertion.
                     For example, "/(?<=\t)\w+/" matches a word that
                     follows a tab, without including the tab in $&.
                     Works only for fixed-width look-behind.
    
    "(?<!pattern)"
                     A zero-width negative look-behind assertion.
                     For example "/(?<!bar)foo/" matches any occur-
                     rence of "foo" that does not follow "bar".
                     Works only for fixed-width look-behind.
    
    Liz
Re: regex match question
by jeffa (Bishop) on Aug 03, 2003 at 17:41 UTC
    Some advice to go along with what liz said. You don't need to 'escape' percent signs and you posted the wrong operator in your code that is broken. Here is that line of code, slightly 'fixed':
    $str =~ s/%q//g;
    All you need to do here is add the zero-width negative look-behind assertion and you are go to go. Think of this as a 'helping you help yourself' solution. ;)

    jeffa

    L-LL-L--L-LL-L--L-LL-L--
    -R--R-RR-R--R-RR-R--R-RR
    B--B--B--B--B--B--B--B--
    H---H---H---H---H---H---
    (the triplet paradiddle with high-hat)
    
      A very minor note about your comment, you don't need to escape percent signs. You're right that it's not necessary, but I don't fault it.

      In the perl5 incarnation, it's been very handy to remember that escaped alphanumerics are special and escaped non-alphanumerics are plain. Thus \s and \3 have special regex meanings while \% and \$ removes any regex meaning and gives literal characters. There are a scant few bits of punctuation which have no meaning in a regex, so I forgive any excess escaping as being more "obvious" or literate to the maintenance coder.

      Perl6 turns regex syntax on its head in many ways (and allows interpolation of hashes), so it'll be interesting to see if there's still an easy mnemonic demarcation between special and literal.

      --
      [ e d @ h a l l e y . c c ]

      you don't need to confuse people with the extra syntax of look-ahead/behind....you just need to match exactly what you want "a non-percent sign character followed by a percent sign character followed by q", i.e. $str =~ s/[^%]%q//g;
        That doesn't work if %q starts the line - try
        /^%q|[^%]%q/

        or use the negative look behind
        /(?<!%)%q/
        In addition to the problem leriksen pointed out, your suggestion deletes an extra character. In order to meet the OP's spec, it gets a bit uglier:
        $str =~ s/^%q|([^%])%q/$1/g;
        Basically, it would be less confusing to learn about zero-width assertions.

        Granted, it does pose a bit of a challenge to "learn" the various zero-width and non-grouping forms. I haven't memorized them yet myself -- I just scan through the "perlre" man page every time I need to use one of those "(?whatever)" thingies. I actually don't mind that. I'm used to it from always having to do the same thing for a dozen different common C library calls -- I still do that, after "knowing" C for 15 years.

Re: regex match question
by Abigail-II (Bishop) on Aug 04, 2003 at 07:21 UTC
    But what if you have %%%q? Should it match the %q or not? If it should, you might want to use:
    s/(%.)/$1 eq "%q" ? "" : $1/eg;

    Abigail