Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl: the Markov chain saw
 
PerlMonks  

R.Exp. Matching from the Right

by Anonymous Monk
on Feb 23, 2006 at 17:04 UTC ( [id://532321]=perlquestion: print w/replies, xml ) Need Help??

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

Hi Monks,
I am trying to match this path:
my $ file = "c:/progra~1/apache~1/apache2/cgi-bin/test/new/Feb23-2006_ +0_test_error.txt"; if($file=~/(.*?)\/(\w+\.txt){ print "### $1 - $2####";}else{print "No + Match";}

I think it will be easy to match from the right because the path could be different sometimes, all I need to get is the file name from the path, I can't figure it out.
Thanks

Replies are listed 'Best First'.
Re: R.Exp. Matching from the Right
by Corion (Patriarch) on Feb 23, 2006 at 17:13 UTC

    You really want File::Basename, which is made for file/directory manipulation.

    But for regular expressions, you want what is called an anchor. There are two (well, technically four) of them: ^ anchors the match to the start of the string, and $ anchors it to the end (see perlre). So your problem could be solved by:

    my $file = "c:/progra~1/apache~1/apache2/cgi-bin/test/new/Feb23-2006_0 +_test_error.txt"; if ($file =~ m!^(.*)/(\w+\.txt)$!) { print "Found $1 - $2\n"; } else { print "No match found for '$file'\n"; };

      There are five anchors:
      without m with m
      Start of string \A and ^ \A
      Start of line ^
      End of string or before \n at end of string \Z and $ \Z
      End of line or before \n at end of line $
      End of string \z \z

Re: R.Exp. Matching from the Right
by ptum (Priest) on Feb 23, 2006 at 17:13 UTC

    You might consider using File::Basename.

    Update: Since [id://Corion] beat me by seconds in answering your question, I'll have to redeem myself by adding a little more detail.

    The reason that [id://Corion]'s solution works is because of regular expression greed. Specifically, the '.*' part of the expression is greedy (since it doesn't have a '?' after it) and it will expand to consume the largest string possible while still leaving a few crumbs for the rest of the regex -- that is, the /(\w+\.txt) part.

    There is probably a better way to describe regular expression greed, but that is the way it has made sense to me.


    No good deed goes unpunished. -- (attributed to) Oscar Wilde
Re: R.Exp. Matching from the Right
by pileofrogs (Priest) on Feb 23, 2006 at 17:15 UTC

    I try to think of what defines the thing I'm looking for. In this case, I'd think it's the last thing in the string, and the string is separated by '/' marks, that would give me a regex like this:

    $file =~ /\/([^\/]+)$/;

    This says, find a '/' followed by one or more non-'/' up until the end of the string. Capture the non-'/' stuff.

    Update: More of a breakdown. Because '/' itself is used by perl to delimit the regex, in order to search for a '/' in a string I escape it in the regex, hence '\/'.

    The bit that looks like '\/([^\/]+)' is saying find a '/' followed by some non-'/' chars. '\/' means find a '/', '([^\/]+)' means get a bunch of non-'/' chars. '[^\/]' matches any character that isn't a '/'. Putting a '+' at the end of '[^\/]' means match 1 or more times, and putting that inside of parenthesis means capture it for a back reference.

    The '$' anchors that to the end of the string.

    Once you look at how a regex works, it can be fun to think about strings that could break it. What would $1 look like if $file were any of these?

    • foo.txt
    • /my/head/hurts/

    Another Update: Great point kwaping! (see below)

      You can use different delimiters for your match, which removes the need to escape your slashes. This may or may not make that line less confusing. :)
      $file =~ m|/([^/]+)$|;
      This one worked great, but can you explain a little how it is doing it? Thanks a lot you all!
        It reads as /, followed by one or more characters which aren't /, followed by the end of string. It works because of backtracking. When it can't find a match with the first slash (because there are other slashes between it and the end of string), it tries starting at a different slash. Rinse and repeat until a match is found, or there are no more slashes at which to start.
Re: R.Exp. Matching from the Right
by Praveen (Friar) on Feb 24, 2006 at 05:46 UTC
    Try This
    my $ file = "c:/progra~1/apache~1/apache2/cgi-bin/test/new/Feb23-2006_ +0_test_error.txt"; print "$'\n", if($file=~/(.*)\//g);
Re: R.Exp. Matching from the Right
by mk. (Friar) on Feb 24, 2006 at 17:14 UTC
    i assume you want the file name, without the path - is it right?! if so, try this:
    (my $file = "c:/progra~1/apache~1/apache2/cgi-bin/test/new/Feb23-2006_ +0_test_error.txt")=~ s/.*\///g; print $file;

    if you want to print the path as well, just use print $&;

    update
    the code above will replace the path with nothing, so the result will be just the filename. you might recover the path later, as i said, using $&.
    still, if you really only want to match, i guess Praveen's reply will be more suitable.
    =)


    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    @

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others surveying the Monastery: (None)
    As of 2024-04-25 01:43 GMT
    Sections?
    Information?
    Find Nodes?
    Leftovers?
      Voting Booth?

      No recent polls found