Beefy Boxes and Bandwidth Generously Provided by pair Networks
Welcome to the Monastery
 
PerlMonks  

Re^2: Regex conditional match if previous match in same expression is true?

by radiantmatrix (Parson)
on Apr 09, 2007 at 18:47 UTC ( [id://609009]=note: print w/replies, xml ) Need Help??


in reply to Re: Regex conditional match if previous match in same expression is true?
in thread Regex conditional match if previous match in same expression is true?

From your expected results, I deduce you actually want a string that is surrounded by {...}, or one that is neither preceded by { nor followed by }.

That's correct: I want the string, optionally surrounded by braces. One brace on only one side is not acceptable. I'm glad that my listing of expected results was clearer than my description. ;-)

Your alternation approach certainly functions. However, I was also hoping to learn to use the conditional ( (?(COND)...) ) notation. So you answered the question I asked (thanks!); but left me with the one I didn't ask.

For my own education, can you think of a solution that uses the conditional notation, or would I be horribly abusing said to solve this problem?

<radiant.matrix>
Ramblings and references
The Code that can be seen is not the true Code
I haven't found a problem yet that can't be solved by a well-placed trebuchet
  • Comment on Re^2: Regex conditional match if previous match in same expression is true?
  • Download Code

Replies are listed 'Best First'.
Re^3: Regex conditional match if previous match in same expression is true?
by ikegami (Patriarch) on Apr 09, 2007 at 19:33 UTC

    can you think of a solution that uses the conditional notation

    The algorithm:

    • Note the preceding character (if any).
    • Match 'hello'.
    • If there was a character to note,
      • If the noted character is {,
        • Match }. ( Oops, I had the brace reversed. )
      • Else,
        • Negatively match }.
    • Else,
      • Negatively match }.

    As it turns out, the "if any" portion of the first step is hard to implement because look-behinds must be fixed-width. So let's make that conditional too:

    • If we are at the start of the string,
      • Match 'hello'.
      • Negatively match }.
    • Else,
      • Note the preceding character.
      • Match 'hello'.
      • If the noted character is {,
        • Match }. ( Oops, I had the brace reversed. )
      • Else,
        • Negatively match }.
    / (?(?<=(.)) # We are not at the start of the string. # The preceding character is in $1. hello (?(?{ $1 eq "\{" }) # The char before 'hello' is '{'. } | # The char before 'hello' is not '{'. (?! } ) ) | # We are at the start of the string. hello (?! } ) ) /x

    Yikes!

      Thank you! That was deeply instructive -- where I work I code primarily in a vacuum (well, there is one other Perl user, but he's just now learning), so it's nice to see the thought process of a more experienced Monk.

      Just out of curiosity, I note that you used the Perl-only capability of executing Perl code inside a conditional. Despite being *way* off topic, I am interested to know if that's really the only sensible way to do this (that is, accomplish my goal using a conditional rather than an alternation). For example, if I were to use Jakarta-ORO (Perl-style regex engine for Java), I suspect I wouldn't have that facility.

      Feel free to /msg me if you don't want to carry this OT discussion in-thread, we could pick it up in e-mail. Or, if you prefer, could you recommend a chapter of Mastering Regular Expressions that covers the topic well? I've bought the book, but haven't yet had the time to read it start-to-finish.

      <radiant.matrix>
      Ramblings and references
      The Code that can be seen is not the true Code
      I haven't found a problem yet that can't be solved by a well-placed trebuchet

        Rhandom provided a better solution. Here's a simplification of it:

        / (?: ({) | (?<!{) ) hello (?(1) } | (?!}) ) /x

        It doesn't "use Perl", but I suspect it won't solve your compatibility problems like you think it will. Are you sure that engine supports conditionals ((?(...)...|...))?

        I've never read "Mastering Regular Expressions".

Re^3: Regex conditional match if previous match in same expression is true?
by demerphq (Chancellor) on Apr 09, 2007 at 22:02 UTC

    Other posters were correct when they changed things from using the {min,max} quantifier notation on the inside of the capture buffer to using the '?' quantifier on the outside. There is a crucial difference between "empty but matching" and "not matching", and {0,1} doesnt have the same behaviour as '?' even though they are functionally equivelent. (This may be construed as a bug :-) Alternatively you can do what i do below, which is to put the capture inside of an alternation.

    Anyway, the following uses the conditional pattern with lookahead/lookbehind to match as you requested. You can play around with it to easily forbid {{hello}}, as the current code allows it.

    use strict; use warnings; for ( 'oh {hello} there', 'oh {hello there', 'oh hello there', 'oh hello} there', 'of {{hello}} there', ) { if ( $_ =~ / (?: ( \{ ) # capture a '{' | # or (?<! \{ ) # not preceded by a '{' ) hello # .. followed by 'hello' (?(1) # if (defined $1) \} # match an '}' | # else (?! \} ) # not followed by a '}' ) # /x) { print "YEP : $_ : ", defined $1 ? "'$1'" : 'undef', " - $&\n"; } else { print "NOPE: $_\n"; } } __END__ YEP : oh {hello} there : '{' - {hello} NOPE: oh {hello there YEP : oh hello there : undef - hello NOPE: oh hello} there YEP : of {{hello}} there : '{' - {hello}

    Also I changed your diagnostic code, you were using $1 even when the match failed, which meant you were getting the wrong thing.

    ---
    $world=~s/war/peace/g

      Hm, I hadn't thought of using alternation in this way. Most helpful, thank you! My comments to ikegami apply to your post as well.

      What do you mean by I was "getting the wrong thing"? I mean, I was attempting to print an undef value, which threw warnings... but was I really getting inaccurate results that way? Mind clarifying a little?

      <radiant.matrix>
      Ramblings and references
      The Code that can be seen is not the true Code
      I haven't found a problem yet that can't be solved by a well-placed trebuchet

        $1 is a dynamically scoped variable that contains details from the last successful match in the current scope. It is NOT set to undef after a failed match.

        Regarding your comments to ikegami, they dont seem so relevent here. I didnt use an eval operator, as for how to accomplish the goal with the conditional pattern and not alternation, well ive already done that havent I? If you mean regarding MRE, id say just work through the book. There is a way of thinking about things that makes regexes easy to understand, and there is a way that will lead to confusion. I dont recall specifically anything that gives a particularly good discussion of the conditional pattern. I have never encountered one in live code.

        ---
        $world=~s/war/peace/g

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://609009]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others contemplating the Monastery: (4)
As of 2024-04-24 18:44 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found