如何用Regex去除文件扩展名,从Linux文件路径提取文件名?
解决Linux文件路径中提取不含扩展名的文件名的正则问题
嘿,我来帮你搞定这个正则的问题!你之前用的^/(.+/)*(.+)/(.+)$确实会把扩展名包含在$3里,而且这个正则还有个小问题——如果路径是像/filename.txt这种一级路径的话,它会匹配失败,因为中间的(.+)/要求必须有一个斜杠加内容。
针对你的需求,我给你两个实用的正则方案:
方案1:提取最后一个点之前的文件名(适合单扩展名或多扩展名场景)
这个方案会把最后一个点之后的部分当作扩展名去掉,不管扩展名有多长(比如.tar.gz会被整体当作扩展名):
^.+/([^/.]+)(?:\.[^/.]+)?/?$
让我拆解一下每个部分的作用:
^.+:匹配从路径开头到最后一个斜杠之前的所有内容/:匹配路径中的最后一个斜杠([^/.]+):核心捕获组,匹配除了斜杠(/)和点(.)之外的所有字符——这就是我们要的不含扩展名的文件名,支持带空格的情况(?:\.[^/.]+)?:非捕获组,可选匹配扩展名(点+非斜杠/非点的字符),?保证没有扩展名的文件也能被正确匹配/?:可选匹配路径末尾的斜杠(避免目录路径干扰,不过你如果确定是文件路径可以去掉)
测试示例:
- 路径:
/snow ninja/Documents/filename.txt→ 捕获组1结果:filename - 路径:
/snow ninja/Documents/my important file.pdf→ 捕获组1结果:my important file - 路径:
/home/user/readme→ 捕获组1结果:readme - 路径:
/data/project/archive.tar.gz→ 捕获组1结果:archive
方案2:保留文件名中的中间点,仅去掉最后一个扩展名
如果你的文件名本身包含点(比如my.report.v2.txt),想提取my.report.v2而不是my,可以用非贪婪匹配的版本:
^.+/(.+?)(?:\.[^/.]+)?/?$
这里把[^/.]+换成了.+?(非贪婪匹配),它会匹配到最后一个点之前的所有内容,包括文件名里的中间点。
测试示例:
- 路径:
/docs/my.report.v2.txt→ 捕获组1结果:my.report.v2
为什么你的原正则不行?
你之前的^/(.+/)*(.+)/(.+)$中,最后一个(.+)是贪婪匹配到路径末尾,所以会把扩展名一起包含进去。而且这个正则要求路径至少有两级(比如/a/b.txt才会匹配,/b.txt不匹配),适用性不如上面的方案广。
内容的提问来源于stack exchange,提问作者kanataki
相关产品推荐
相关产品推荐

