Beefy Boxes and Bandwidth Generously Provided by pair Networks
No such thing as a small change

matching constants within a regular expression?

by Anonymous Monk
on Mar 10, 2004 at 22:48 UTC ( #335644=perlquestion: print w/replies, xml ) Need Help??

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

I'm fighting syntax issues and losing when trying to match a constant's value within a regular expression. Searching the archives yielded, but I'm still getting syntax errors. A simplified test case is:
#!/usr/bin/perl use strict; use warnings; use constant { ATTRIBUTE_0 => 'foo', ATTRIBUTE_1 => 'bar' }; open IN, 'input.xml' or die 'unable to open input XML file'; while (<IN>) { print "attribute 0=\t$1\n" if m/@{ATTRIBUTE_0}='(.*)'/e; print "attribute 1=\t$1\n" if m/@{ATTRIBUTE_1}='(.*)'/e; } close IN;
Can you help me over these syntax issues? Thanks.

Replies are listed 'Best First'.
Re: matching constants within a regular expression?
by Paladin (Vicar) on Mar 10, 2004 at 23:00 UTC
    Constants in Perl declared with use constant are actually subs. The regex in m/.../ first goes through double quoted string-ish interpolation, and the general way to interpolate a sub call within a string is:
    $var = "foo @{[ sub() ]} baz"; # Note: This calls the sub in list context, so may have a # different effect than if called in scalar context. Use # ${ \sub() } for scalar context.

    Also, the /e modifier is for the s/// operator, not the m// operator, hence the syntax errors you are getting.

    So you would want something like:

    print "attribute 0=\t$1\n" if m/@{[ATTRIBUTE_0]}='(.*)'/;

    It looks kind of ugly, but it works.

Re: matching constants within a regular expression?
by elusion (Curate) on Mar 10, 2004 at 23:15 UTC
    Thank you for searching before you ask! That is always appreciated. One little note about your link though: Perlmonks has a special linking system that you should use. Your link goes to, while many monks, myself included, use, which means we aren't logged in when we follow your link.

    Instead, you should link like this: [id://293323] or [use of constants in regex substitutions?], which will yield use of constants in regex substitutions?. (See What shortcuts can I use for linking to other information?)

    Now on to your question. :-) The node you linked to does in fact include the answer, which I will explain for you. You want to use: print "attribute 0=\t$1\n" if m/${\ATTRIBUTE_0}='(.*)'/;

    Here's the reasoning. When you create a constant, like ATTRIBUTE_0 and ATTRIBUTE_1, you're really creating a special subroutine. The reason it works is because perl knows you aren't going to pass it any parameters, so it can insert the value from the sub at compile time.

    This means that when you use the constant in your regex, you need to access it like a subroutine. You do this by creating a reference to its value and dereferencing that reference. The \ creates the code reference and the ${} dereferences it. For more info see: perlref.

    I hope this helps!

Re: matching constants within a regular expression?
by thelenm (Vicar) on Mar 10, 2004 at 23:00 UTC

    I think what you want is ${\ATTRIBUTE_0} or @{[ATTRIBUTE_0]}.

    What you have, @{ATTRIBUTE_0}, is basically the same as @ATTRIBUTE_0 without the braces.

    -- Mike

    XML::Simpler does not require XML::Parser or a SAX parser. It does require File::Slurp.
    -- grantm, perldoc XML::Simpler

Re: matching constants within a regular expression?
by BrowserUk (Pope) on Mar 10, 2004 at 23:12 UTC

    Whether this is any less ugly you'll have to make your own mind up about.

    use constant FRED=>'fred'; my @s = qw[ the=the quick=quick brown=brown fred=fred1 jumped=jumped over=over the=the lazy=lazy fred=fred2 ]; $_ =~ ( FRED . '=(.*)$' ) and print "Found $1" for @s; Found fred1 Found fred2

    Examine what is said, not who speaks.
    "Efficiency is intelligent laziness." -David Dunham
    "Think for yourself!" - Abigail
Re: matching constants within a regular expression?
by matija (Priest) on Mar 10, 2004 at 23:07 UTC
    Two problems with your code
    • the e modifier does not work for matches (m//), only for substitutes (s///).
    • The @{ATTRIBUTE} form is incorrect (it even says to in the SOPW you pointed at)
    The correct (i.e. no syntax errors, I can't vouch against logic errors) code is:
    print "attribute 0=\t$1\n" if m/${\ATTRIBUTE_0}='(.*)'/; print "attribute 1=\t$1\n" if m/${\ATTRIBUTE_1}='(.*)'/;

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://335644]
Approved by Paladin
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others scrutinizing the Monastery: (5)
As of 2021-04-19 06:41 GMT
Find Nodes?
    Voting Booth?

    No recent polls found