Beefy Boxes and Bandwidth Generously Provided by pair Networks
Clear questions and runnable code
get the best and fastest answer
 
PerlMonks  

file name parsing to get the original file name

by tja_ariani (Acolyte)
on Aug 19, 2003 at 10:57 UTC ( #284844=perlquestion: print w/ replies, xml ) Need Help??
tja_ariani has asked for the wisdom of the Perl Monks concerning the following question:

Hi Perl Monks,

I have a string of filename that looks something like this :
xxx/yyy/zzz.a

My goal is to get the file name only (zzz.a).

Is there any built in function in CGI/perl to do this, or how should I do this in case there is no built in function available ?

Thanks

Comment on file name parsing to get the original file name
Re: file name parsing to get the original file name
by Abigail-II (Bishop) on Aug 19, 2003 at 11:04 UTC
    use File::Basename;

    The module comes standard with modern versions of Perl.

    Abigail

      Or perhaps this bit of nasty perl code:

      my($file)=[reverse split(/[\/\\]/,$fullpath)]->[0];

      It's the kind of dirty hackish code that will make programmers modifying your program years down the road curse your name, but it works.

        This is suboptimal. First, it isn't right on all platforms. On UNIX, a file or directory name could contain a backslash, but your regex splits on backslashes. Second, it's inefficient. If you want to take the last element of a list, take the last one, instead of first reversing the list, then putting into an anonymous array, then take the first element of that. As I indicated elsewhere in this thread:
        my $file = (split m{/} => $fullpath) [-1];

        Abigail

Re: file name parsing to get the original file name
by arthas (Hermit) on Aug 19, 2003 at 13:24 UTC
    As Abigail-II suggested, use File::BaseName. However, if you are parsing HTML form input, beware: the module is not going to work regardless of the operating system of the client. Windows machines put backslashes (\) instead of slashes (/) for instance, so if you need to receive file uploaded by a Windows client and your program is on an Unix server, you'll need to do:

    fileparse_set_fstype("MSWin32");

    before calling the parsing function. The default FS type of the module depends on the operaing system where the script runs (it's decided upon examining the $^O variabile).

    Michele.

      My general rule of thumb is to use forward slashes wherever you can get away with it, and use OS-specific separators only when testing shows that they're required. Be ready to accept the OS-specific separators or the forward slashes whenever the user supplies them.

      I just tried this test on Windows with Perl 5.6.0. It shows that File::Basename accepts forward or backslashes on Windows. This is not a thorough test on all platforms and versions.

      use File::Basename qw(basename dirname); print basename("c:\\path\\file.txt"), $/; print basename("c:/path/file.txt"), $/; print dirname("c:\\path\\file.txt"), $/; print dirname("c:/path/file.txt"), $/; __OUTPUT__ file.txt file.txt c:\path c:/path

      "Be lenient in what you accept, strict in what you produce."

      --
      [ e d @ h a l l e y . c c ]

        Output on a Linux box is...
        c:\path\file.txt
        file.txt
        .
        c:/path
        
        ...which is obviously wrong if you need to deal with the win32 input.
      Hi Michele,

      I was trying your solution since my parsing is indeed HTML form input.Tried the other solutions but can't work, it still does not recognize the '\'

      Is there anything that I should need to add before inserting the :
      fileparse_set_fstype("MSWin32");
      Because my html shows an error when I add that line.

      Thanks

        Hi all,

        Thanks for the help, for my post just now I realized that the use File::Basename shouldn't use the qw(...)

        Thanks

Re: file name parsing to get the original file name
by bear0053 (Hermit) on Aug 19, 2003 at 13:55 UTC
    you can also do the following (maybe a little less efficient way but at least you won't need to require another module)
    my $filename = 'xxx/yyy/zzz.a'; my ($tmp1,$tmp2,$name) = split(/\//,$filename); print "$name";
    $name from above will now contain zzz.a
      That's not very flexible. I can understand not needing to care about separators from different platforms, but your approach only works if you have two directories and then the file. It will fail if there's just one directory, or three.

      my $filename = "one/two/three/four/five/six.a"; my $name = (split m{/} => $filename) [-1];

      Abigail

        If we are trying for 'best UNIX-only solution that requires no modules', I vote for:

        my($name) = $path =~ /([^\/]+)\z/;

        I second Abigail-II's suggestion that a module is used, though, as these sorts of problems are generic in nature, and it is very scary to see hundreds of different solutions to the same problem, each with their own independent set of failings.

        At least if a single module is used by everybody, then the code is being excercised in a higher percentage of the possible contexts, and problems will be fixed sooner, rather than being discovered much later.

        UPDATE: Optimizing the above expression, we can see the speed improve by a factor of 6:

        $path =~ /(?:.*\/)?(.+)/s; my $name = $1;

        It seems that the Perl regular expression engine does a poor job of dealing with matching a pattern at the end of a string. This is not surprising given that most regular expression engines start searching from the beginning of the string.


        Reason: Zaxo delete, dupe

        For more information on this node visit: this

Log In?
Username:
Password:

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

How do I use this? | Other CB clients
Other Users?
Others imbibing at the Monastery: (13)
As of 2014-10-02 14:30 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    What is your favourite meta-syntactic variable name?














    Results (61 votes), past polls