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

Hi Monks,

This seems to be a fairly easy question but I cannot figure it out. I have a string which is a unix pathname /a/b/c/d/e/f and wish to extract only the first 3 fields. The closest I have got is using split and join:

my $a = "/a/b/c/d/e/f"; my @foo = (split /\//,$a)[1..3]; my $y = join ('/',@foo); $y =~ s#^#/#; print "Y = $y\n";
There's got to be an easier way to achieve this. Can someone show me how?

Thanks

Replies are listed 'Best First'.
Re: Extract portion of string based on string separator
by GrandFather (Saint) on Apr 26, 2007 at 00:42 UTC

    File::Spec is likely to be a more portable and less fussy way of managing path manipulations:

    use strict; use warnings; use File::Spec::Functions qw(splitdir catdir splitpath); my $path = "/a/b/c/d/e/f"; my @foo = splitdir ($path); my $subpath = catdir (@foo[1..3]); # Note that the "volume" is blank s +o skip that print "Sub path = $subpath\n";

    Prints:

    Sub path = a\b\c

    DWIM is Perl's answer to Gödel
Re: Extract portion of string based on string separator
by ikegami (Patriarch) on Apr 26, 2007 at 00:37 UTC

    The following two also works:

    my ($y) = '/a/b/c/d/e/f' =~ m{^(/[^/]+/[^/]+/[^/]+)};
    my $y = join('', (split(qr{(?=/)}, '/a/b/c/d/e/f'))[0..2]);

    By the way, using $a is a bad habit. Declaring it as a lexical, doubly so.

      Depending a bit on whom eyes for your code goes, you might want to restyle ikegami's first suggestion above to something like
      use strict; use warnings; my $path_head = _get_first_3( '/a/b/c/d/e/f' ); sub _get_first_3 { my ($path) = @_; my $path_part = qr{ [^/]+ }x; # whatever char except slash my $path_head_regex = qr{ ( \A # beginning of string ( / $path_part) {3} ) # /three/part/parts here }x; my ($head) = ($path =~ m{ $path_head_regex }x); return $head; }
        ikegami,GrandFather and Krambambuli,

        Thank you very much for the insightful solutions. I particularly liked Krambambuli's method of writing a subroutine for extracting the first n members. I have yet to understand how it works though.

        Best Regards,

Re: Extract portion of string based on string separator
by jdporter (Paladin) on Apr 26, 2007 at 21:03 UTC
    Here's a couple of generic functions which you can re-use for similar purposes later.
    sub path_parts(@) { shift=~m((/[^/]*))g } sub limit_list($@) { $#_=-1+shift; @_ }
    You can use them for your current problem like this:
    my $orig_path = "/a/b/c/d/e/f"; my $trunc_path = join '', limit_list( 3, path_parts( $orig_path ) );
    A word spoken in Mind will reach its own level, in the objective world, by its own weight
Replacing one regex in your ury
by TomDLux (Vicar) on Apr 26, 2007 at 20:41 UTC

    Not related to your question, just to my bugbear---people using regex for trivial operations.

    Regexes are complicated machines with significant overhead. Using one to prepend a character irritates. It's like using a 747 to get milk from teh corner store.

    How about doing something like ...

    my $y = '/' . join '/', @foo );

    Maybe I should change my nick to GrumpyOldMan ... my friends can call me GOM

    Tom
    --
    TTTATCGGTCGTTATATAGATGTTTGCA