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

What in the world am I missing?

The error is in your problem definition. Your regexp does exactly what you said you wanted it to do. It's searching for a string optionally surrounded by '{' and '}'. {hello is optionally surrounded by {...} since it's is not surrounded by {...}.

'oh {hello there' =~ / ([{]{0,1}) # Matches '' (after some backtracking) hello # Matches 'hello' (?(1)\}) # Matches '' /x;
'oh hello} there' =~ / ([{]{0,1}) # Matches '' hello # Matches 'hello' (?(1)\}) # Matches '' /x;

As you can see, searching for a string optionally surrounded by something is the same thing as searching for the string itself.

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 }.

/ {hello} # '{hello}' | (?<! { ) # Not preceded by '{' hello # 'hello' (?! } ) # Not followed by '}' /x

Replies are listed 'Best First'.
Re^2: Regex conditional match if previous match in same expression is true?
by radiantmatrix (Parson) on Apr 09, 2007 at 18:47 UTC

    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

      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

      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