为什么我的Perl正则表达式没有正确地从路径中提取文件名?

时间:2010-05-18 16:10:13

标签: perl

我试图从路径解析文件名。我有这个:

my $filepath = "/Users/Eric/Documents/foldername/filename.pdf";
$filepath =~ m/^.*\\(.*[.].*)$/;
print "Linux path:";
print $1 . "\n\n";
print "-------\n";

my $filepath = "c:\\Windows\eric\filename.pdf";
$filepath =~ m/^.*\\(.*[.].*)$/;
print "Windows path:";
print $1 . "\n\n";
print "-------\n";

my $filepath = "filename.pdf";
$filepath =~ m/^.*\\(.*[.].*)$/;
print "Without path:";
print $1 . "\n\n";
print "-------\n";

但是回归:

Linux path:

-------
Windows path:Windowsic
                      ilename.pdf

-------
Without path:Windowsic
                      ilename.pdf

-------

我期待着这个:

Linux path:
filename.pdf
-------
Windows path:
filename.pdf
-------
Without path:
filename.pdf
-------

有人可以指出我做错了吗?

谢谢! :)

4 个答案:

答案 0 :(得分:7)

在这种情况下,正如其他人所说,错误就是手工完成。

File::Basename外,您还应该查看File::SpecPath::Class。它们提供经过充分测试的跨平台方法来处理文件和目录。 Path::Class特别提供了帮助方法来处理脚本所在系统的外来文件和目录名。看起来这可能会派上用场。

#!/usr/bin/env perl
use strict;
use warnings;
use Path::Class qw/file foreign_file/;

my $nix = "/Users/Eric/Documents/foldername/filename.pdf";
my $win = 'c:\\Windows\eric\filename.pdf'; # single quote to avoid escape issues

print file($nix)->basename(), "\n";
print foreign_file('Win32', $win)->basename(), "\n";

答案 1 :(得分:4)

为什么不使用File::Basename

$name = basename($filepath)
print $name

正则表达式

m/^.*\\(.*[.].*)$/
#    ^^

假定分隔符\,因此情况1和3永远不会匹配。在案例2中,

"c:\\Windows\eric\filename.pdf";

\e\f都是Perl中的特殊字符。所以代码“正确”返回Windows\eric\filename.pdf作为文件名。请记住使用\\

答案 2 :(得分:3)

Perl提供此功能: http://perldoc.perl.org/File/Basename.html

你还需要警惕字符串转义 - 你的Windows路径字符串在'\','\ f'和'\ e'上被转义 - 自从我处理Perl转义以来已经有一段时间了,但是我猜测\ e也在吞下'r'之后。这解释了意外的输出。

答案 3 :(得分:2)

嗯,正在发生的事情的答案是:各种错误。

my $filepath = "/Users/Eric/Documents/foldername/filename.pdf";
$filepath =~ m/^.*\\(.*[.].*)$/;
print "Linux path:";
print $1 . "\n\n";
print "-------\n";

$filepath中没有\\个,因此它不匹配且没有$1。你把/放进去了。你的表达必须是:

# regular expression matches return their captures in a list context.
my ( $path ) = $filepath =~ m|/([^/.]*\.[^/.]*)$|;
print "Linux path:$path\n\n-------\n"; # little need to . a " string

my $filepath = "c:\\Windows\eric\filename.pdf";
$filepath =~ m/^.*\\(.*[.].*)$/;
print "Windows path:";
print $1 . "\n\n";
print "-------\n";

你正在使用双引号,它从UNIX shell中获得提示,比单引号字符串更活跃。因此,您需要转义所有反斜杠,如下所示:

my $filepath = "c:\\Windows\\eric\\filename.pdf";

或只使用单引号:

my $filepath = 'c:\Windows\eric\filename.pdf';

实际上,由于perl了解'/'的窗口,这也适用(但不适用于正则表达式。)

my $filepath = "c:/Windows/eric/filename.pdf";

只要您在将其交还给Windows之前修复它。

my $filepath = "filename.pdf";
$filepath =~ m/^.*\\(.*[.].*)$/;
print "Without path:";
print $1 . "\n\n";
print "-------\n";

这不是匹配,因此$1仍然是最后一场比赛。这就是重复的原因。但这指出了捕获捕获的价值而不是引用$1