Perl正则表达式替换最后一个匹配的字符串

3

我有一个如下的字符串:

$str = "/dir1/dir2/dir3/file.txt"

我想把这个字符串中的 /file.txt 删除。

这样 $str 就变成了。

$str = "/dir1/dir2/dir3"

我正在使用以下正则表达式,但它正在替换所有内容。
$str =~ s/\/.*\.txt//;

如何使正则表达式查找最后一个'/'而不是第一个。

正确的正则表达式是什么?

请注意,file.txt不是固定名称。它可以是任何像file1.txtfile2.txt等的名称。

3个回答

6
如果你想从该字符串中获取路径,可以使用File::Basename。它是自Perl 5版本以来的核心模块。
perl -MFile::Basename -le '$str = "/dir2/dir3/file.txt"; print dirname($str);'

在脚本形式中:
use strict;
use warnings; # always use these
use File::Basename;

my $str = "/dir1/dir2/dir3/file.txt"; 
print dirname($str);"

您的正则表达式无法工作,因为它没有锚定,并且.*是贪婪的,所以它会尽可能地匹配,从第一个斜杠/开始。一个有效的正则表达式应该像这样:

$str =~ s#/[^/]*?\.txt$##;

请注意使用非贪婪量词*?,它将匹配最小可能的字符串。另外请注意我使用了另一个替换分隔符以避免“倾斜牙签综合症”,例如s/\/\/\///

感谢您向我介绍File::Basename和详细的解释。 - AnonGeek
@Saumitra 不用客气。你不应该害怕使用模块。这个模块已经在你的系统上可用(除非你的 Perl 安装已经有 20 年了)。 - TLP
3
像往常一样,好的代码和好的建议。但有时我喜欢使用 rindex($str,'/') - gaussblurinc
@loldop 这是一个非常干净的方法。我完全忘记了那个函数。 - TLP

3
非常简单的正则表达式: s/\/[^\/]*$//

@Saumitra那是因为他忘记了即使在字符类内部也必须转义分隔符“/”。 - TLP

2
在这个正则表达式中
m/(.*)\/[^\/]*$/

第一个子匹配是您要查找的路径。

编辑:

如果您正在寻找替换方案,请使用user1215106的解决方案。

s/\/[^\/]*$//

你还忘记在字符类中转义定界符了。 - TLP
@Saumita - 你接受了这个答案?这对你有用吗?请参见 http://ideone.com/GVagS - 它会给你一个空字符串。正解应该是 s/(.*)\/[^\/]*$/$1/ 或者 s/\/[^\/]*$//,就像我在答案中展示的那样。 - Ωmega
@Saumita - 是的,$1 匹配了它,但是他使用的替换s/../../是用于修改而不是匹配,所以他清除了输入字符串 - 在这里看:http://ideone.com/K5qe2 - Ωmega
@Saumitra 用户1215106的意见是正确的,因为这个解决方案是具有破坏性的。使用他的解决方案,您将获得完全相同的结果,而无需破坏原始数据。当然,File::Basename甚至不会改变您的变量。 - TLP
@flec - 这不是关于争论,而是关于正确的答案,这样下一个用户在寻找类似或相同任务时就可以阅读到正确的解决方案。我很高兴你编辑了你的答案并进行了更正。现在没问题了。谢谢并祝好运! - Ωmega
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接