Beefy Boxes and Bandwidth Generously Provided by pair Networks
Keep It Simple, Stupid
 
PerlMonks  

qr// with /e?

by tkil (Monk)
on Apr 23, 2004 at 21:48 UTC ( [id://347761]=perlquestion: print w/replies, xml ) Need Help??

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

Does anyone else think that adding /e to qr// would be a good idea? I recently found myself doing something like this:
my @days = qw( Sun Mon Tue Wed Thu Fri Sat ); my $days_re = qr/join '|', @days/e;
And was quite surprised that it didn't just work. There are obvious workarounds, but they feel awkward:
my $days_re = do { my $tmp = join '|', @days; qr/$tmp/ };
(Yes, in this particular case, I could abuse $"... but that still takes a do BLOCK and a local.)

Update

  1. Yes, I know that this is not how the language works right now. What I was trying to ask is whether others thought this might be an interesting or useful or non-damaging feature.
  2. Note that I am only suggesting /e apply to the regex guts in qr//. Not in m//, not in s///.
  3. I tried to demonstrate in my example that I would like the /e to apply exactly once, at the time the qr// is evaluated. I understand that this is not how the other qr// modes work (as they are applied at time of use). This is exactly the sort of wart that I was hoping people would point out, and it is appreciated.
  4. I also discussed this on at least one PM list, so I might be confused about what I clarified there vs. what I clarified here. :) Apologies!

So far, people (including myself! :) have demonstrated that this is not a necessary feature. The opinion seems mostly against whether this would be a desirable feature.

It is just a pattern that I've found myself using quite often lately. My preference for a one-line approach is that I like the most important things to be closer to the left side: what I really want to know is that I'm compiling a regex object. Whether I'm building it via a perl expression or by string expansion or by literal is less important to me.

Replies are listed 'Best First'.
Re: qr// with /e?
by kvale (Monsignor) on Apr 23, 2004 at 22:05 UTC
    //e is used for replacement, not matching, so it doesn't seem natural to me. This seems pretty simple:
    my $patt = join '|', @days; my $days_re = qr/$patt/;
    But if you insist on putting it all on one line, try
    my $days_re = qr/@{ [join '|', @days] }/;

    -Mark

      My main objection to the two-line method is that it leaves the first value in scope for no good reason. This is exactly why I used the do BLOCK construct in my "workaround", so that the temporary value is never seen outside the assignment.

      And qr// is a bit of an odd duck, anyway; it isn't doing actual matching. In a sense, it is replacing a string with a regex. So I don't find /e all that unnatural.

      But one of the reasons I asked here was to get others' opinion on the matter. Thanks for the feedback, and I'm curious what others will have to say about it. :)

        To avoid the extra variable hanging around, can't you just do:

        my $days_re = join('|', @days); $days_re = qr/$days_re/;

        Of course, I'd like some way to aggregate regular expressions and nicely apply operations like "concatenate" or "alternative" to them without having to drop back into string representations - that is, I'd like to be able to do:

        my @days = qw( Sun Mon Tue Wed Thu Fri Sat ); my $days_re = re_alternative(map {qr/\Q$_\E/} @days);

        Right now you have to do this, which is ok I guess, but I wonder if there are efficiency issues with the regular expression constructed this way:

        my @days = qw( Sun Mon Tue Wed Thu Fri Sat ); my $days_re = join("|", map {qr/\Q$_\E/} @days); $days_re = qr($days_re);
        -- @/=map{[/./g]}qw/.h_nJ Xapou cets krht ele_ r_ra/ map{y/X_/\n /;print}map{pop@$_}@/for@/
Re: qr// with /e? (E)
by tye (Sage) on Apr 23, 2004 at 23:04 UTC

    I like the idea. I think it could lead to confusion because it would mean that qr/foo/e will be quite different from s/foo/bar/e. But why restrict this useful idea to just qr//. Call it /E and support it on m//, qr//, and s///!

    - tye        

Re: qr// with /e?
by davido (Cardinal) on Apr 24, 2004 at 06:14 UTC
    The fact is that /e is only applicable to the right-hand-side of a s/// operator. In other words, you can't use /e to evaluate code on s/this side//e. It only affects s//this side/e.

    qr//, builds up the RE that can be used on s/this side// of the s/// operator. Thus, just as /e has no relevance to m//, it has no relevance to qr//, nor to s/this side//.

    perlretut discusses this briefly: "A modifier available specifically to search and replace is the s///e evaluation modifier. s///e wraps an eval{...} around the replacement string and the evaluated result is substituted for the matched substring. s///e is useful if you need to do a bit of computation in the process of replacing text."

    You're talking, it seems, about allowing the actual RE portion to be eval{...}'ed prior to the execution of the RE. That is going to be a tough sell and my suspician is that it's going to be nearly impossible to implement correctly. After all, if you eval m/$var+1/ prior to using it as a regexp, is it "$var plus one", or is it "$var repeated one or more times, followed by a 1 character"? And should $var be interpolated prior to the eval, or after the eval but prior to the execution of the RE? Things are tricky enough when it comes to getting it right with the quoted version of eval. Imagine trying to deal with the affects of the RE quote-like operator on top of your eval!


    Dave

      The fact is that /e is only applicable to the right-hand-side of a s/// operator.

      Please see my clarification(s) to my original post on this thread. I'm quite aware of (although I was somewhat taken aback by) the current behavior.

      I was looking for others' opinions on this idea. And I've gotten some (mostly indifferent to negative, alas).

      It seems that what I really want is a way to apply qr to an expression without having to stick it into a variable first. Upthread someone suggested an explicit Regex->new( EXPR ) syntax; my response was to just use qr->( EXPR ). (Sigh, that would break if someone used hyphens as the non-alphanumeric delimiters...)

      (This is, in my mind, a similar situation that \Q and \E found themselves in; being able to escape metacharacters is useful even outside of double-quoted interpolation, so quotemeta is available as a standalone. Hm. Maybe quoteregex is where it's at? Although introducing a new keyword is probably not going to happen...)

      You're talking, it seems, about allowing the actual RE portion to be eval{...}'ed prior to the execution of the RE.

      I realize that it could seem that way, but my request for /e is much closer in spirit to /o than to any of the other match modes. I would only want the /e to apply when qr// is compiling the expression: it would tell qr that the text inside the brackets should be evaled to return a string, as opposed to interpreting the text between the brackets as a value to be double-quote interpolated to return a string. (This is why it seems to resonate with s///e, as the modifier is saying exactly the same thing about the replacement text.)

      Anyway. It's absolutely not necessary, I was just curious what other people thought of the idea. Thanks for your feedback!

        I'm starting to gain a better understanding of your point. But just remember this: According to the "Gory details of parsing quoted constructs", the following steps take place:

        1. Finding the end. (Compiletime)
        2. Removal of backslashes before delimiters. (Compiletime)
        3. Interpolation. (Compiletime)
        4. Interpolation of Regular Expressions. (Runtime)
        5. Optimization of RE Code (Runtime)

        My question is how would you suggest /e be implemented: Before step 3, or after it? I don't know the answer to this, and I'm not sure what the ramifications would be. Currently the quoted version of eval interpolates variables in step 3, and that's why you sometimes have to escape variable names to delay their evaluation until execution time. It seems that it's destined to be a convoluted road to travel.


        Dave

Re: qr// with /e?
by Fletch (Bishop) on Apr 24, 2004 at 01:17 UTC

    I'd be more for a Regexp->new( ... ) which stringifies its argument and then does the qr//. None of the other of the quotelike operators (q// et al) have suffixes so it doesn't seem regular (although it would be orhtogonal to the usage with s///).

    Update: Ooh, good point davido. Of course one might say that the trailing flags are really just syntactic sugar for embedded flags a la qr/(?imosx:...)/.

      "None of the other quotelike operators (q// et al) have suffixes so it doesn't seem regular..."

      But qr// already does have other suffixes. See perlop under "Regex Quote Like Operators". qr// allows for qr//imosx. So the reason for not adding /e can't be because other quote-like operators don't have modifiers. The main reason is that it doesn't make sense since /e only causes an eval{} block to wrap around the right-hand portion of a s/// operator, and qr// doesn't construct that right-hand portion in the first place.

      tie probably had it; don't call it /e. Call it /E or something else to avoid confusion with the longstanding function of the /e modifier.


      Dave

      I'd be more for a Regexp->new( ... ) which stringifies its argument and then does the qr//.

      Hm. qr->( EXPR ) maybe?

      None of the other of the quotelike operators (q// et al) have suffixes so it doesn't seem regular (although it would be orhtogonal to the usage with s///)

      Heh. I wonder if this would fly if I suggested the name qre//? :)

Re: qr// with /e?
by duff (Parson) on Apr 23, 2004 at 22:53 UTC
    Sounds useful to me.
Re: qr// with /e?
by Anomynous Monk (Scribe) on Apr 25, 2004 at 04:59 UTC
    I can think of a couple ways to do that now: $re = qr/${\do{join '|', @days}}/ (as you would interpolate any expression in to any double-quotish construct), or $re = qr/(??{join '|', @days})/ which only evaluates the code when the regex is actually executing (and indeed may evaluate it more than once if backtracked over).

    Both forms may have problems with finding the end of the code given e.g. an unmatched } within the code; the latter currently has unfortunate interaction with lexical vars.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://347761]
Approved by sgifford
Front-paged by broquaint
help
Chatterbox?
and the web crawler heard nothing...

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

    No recent polls found