Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl Monk, Perl Meditation
 
PerlMonks  

Regular Expression Help

by Anonymous Monk
on Nov 18, 2005 at 19:50 UTC ( [id://509925]=perlquestion: print w/replies, xml ) Need Help??

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

Let's say you have a directory:

/rootdir/sub1/sub2/sub3/sub4/

How would I strip off JUST the last subdir, sub4? Of course, the dir could be called anything, like "/rootdir/sub funky ---doodash/la la la/Proposal for Buttering My Feet" and I would still want to strip off "Proposal for Buttering My Feet", and be 5 or more times long.
Any idea? I figure it's a reg ex like "Look for the last / that isn't the last character and take away everything to the right of it, including itself"
Thanks very much!!!!

Replies are listed 'Best First'.
Re: Regular Expression Help
by Fletch (Bishop) on Nov 18, 2005 at 19:58 UTC
Re: Regular Expression Help
by ikegami (Patriarch) on Nov 18, 2005 at 20:45 UTC

    Both are the following portable and reliable. There difference is what happens when the trailing slash is ommited.

    1) Anything after the last slash is considered a dir name:

    my ($vol, $dirs) = File::Spec->splitpath($path, 1); $dirs = File::Spec->canonpath($dirs); my @dirs = File::Spec->splitdir($dirs); pop(@dirs); $dirs = File::Spec->catdir(@dirs); $path = File::Spec->catpath($vol, $dirs, '');

    Test:

    outputs:

    /rootdir/sub1/sub2/sub3/sub4/ -> \rootdir\sub1\sub2\sub3 /rootdir/sub1/sub2/sub3/sub4 -> \rootdir\sub1\sub2\sub3 /rootdir/ -> \ /rootdir -> \ / -> \ C:\ -> C:\ reldir/sub1/ -> reldir reldir/sub1 -> reldir reldir/ -> reldir ->

    2) Anything after the last slash is considered a file name:

    my ($vol, $dirs) = File::Spec->splitpath($path, 0); $dirs = File::Spec->canonpath($dirs); my @dirs = File::Spec->splitdir($dirs); pop(@dirs); $dirs = File::Spec->catdir(@dirs); $path = File::Spec->catpath($vol, $dirs, '');

    Test:

    outputs:

    /rootdir/sub1/sub2/sub3/sub4/ -> \rootdir\sub1\sub2\sub3 /rootdir/sub1/sub2/sub3/file -> \rootdir\sub1\sub2 /rootdir/ -> \ /rootfile -> \ / -> \ C:\ -> C:\ reldir/sub1/ -> reldir reldir/file -> reldir/ -> relfile ->

    Note: The only difference is the second argument to splitpath.

Re: Regular Expression Help
by pg (Canon) on Nov 18, 2005 at 20:16 UTC

    Or utilize rindex: (this code works regarless whether there is a trailing /)

    use strict; use warnings; { my $str = "/rootdir/sub1/sub2/sub3/sub4/"; print substr($str, 0, rindex($str, "/", length($str) - 2)); } print "\n"; { my $str = "/rootdir/sub1/sub2/sub3/sub4"; print substr($str, 0, rindex($str, "/", length($str) - 2)); }

    which prints:

    /rootdir/sub1/sub2/sub3 /rootdir/sub1/sub2/sub3
Re: Regular Expression Help
by ikegami (Patriarch) on Nov 18, 2005 at 20:18 UTC
Re: Regular Expression Help
by Anonymous Monk on Nov 19, 2005 at 00:30 UTC
    Interesting, I think 'split' when I see something separated by slashes. Off the top of my head, the below code will do what you are looking for:
    my @dirs = qw ( /usr/local/bin/ /var/tmp/somefile / /home/foo/bar ); foreach ( @dirs ) { my @dir; my $lastdir; if ( /^\/$/ ) { $lastdir = "/"; print "$lastdir\n"; next; } if ( /\/$/ ) { chop; } @dir = split('/'); $lastdir = pop(@dir); print "$lastdir\n"; }
    Will print:

    bin
    somefile
    /
    bar

    Sorry if this is hacky code. I'm a Monks newb and have made my career by pounding out this type of randomness.
Re: Regular Expression Help
by ercparker (Hermit) on Nov 19, 2005 at 04:51 UTC
    This strips off the last directory if more than one directory in path:
    foreach my $path (<DATA>) { chomp($path); $path =~ s{(?<=[^/])/[^/]+/?$}{}xms; print $path . "\n"; } __DATA__ /rootdir/sub funky ---doodash/la la la/Proposal for Buttering My Feet /rootdir/sub1/sub2/sub3/sub4/ /rootdir/sub1/sub2/sub3/sub4/file/ /rootdir/ /
    Hope this helps
Re: Regular Expression Help
by TedPride (Priest) on Nov 18, 2005 at 23:38 UTC
    All of the regexes listed above seem to have problems in one or more situations.
    use strict; use warnings; while (<DATA>) { chomp; my ($last) = m|/([^/]+)/[^/]*$|; print "$last\n"; } __DATA__ /rootdir/sub1/sub2/sub3/sub4/ /rootdir/sub1/sub2/sub3/sub4/file /rootdir/ /
Re: Regular Expression Help
by ptum (Priest) on Nov 18, 2005 at 19:57 UTC
    /.*\/(.*?)$/ will do the trick, I think. Regular expression greed will consume everything up until the last '/' with the first .* and leave only the last subdir.
      It doesn't work.
        Fletch is right -- use File::Basename -- but in the more general case of finding the last token in a string, that regex ought to work:
        #!/usr/local/bin/perl use strict; my $string = '/one/two and three/and four / and five'; if ($string =~ /.*\/(.*?)$/) { print "Last token: $1\n"; }
        Or you could always split on your token separator and grab the last element in the resulting array.

Log In?
Username:
Password:

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

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

    No recent polls found