如何在JavaScript中从字符串中删除文件扩展名?

505

比如,假设 x = filename.jpg,我想要得到 filename,其中filename可以是任何文件名(为了简化,我们假设文件名只包含 [a-zA-Z0-9-_])。

我在DZone Snippets上看到了 x.substring(0, x.indexOf('.jpg')),但是 x.substring(0, x.length-4) 会更好吗?因为 length 是一个属性,不进行字符检查,而 indexOf() 是一个函数,会进行字符检查。


基本上和 https://dev59.com/OHI-5IYBdhLWcg3wKE-x 一样。除非你要做很多这样的事情,否则担心效率是过早优化。 - The Archetypal Paul
在ES6时代,如果你正在使用nodejs或适当的转译,请查看Path模块。 - Frank N
27个回答

640

不确定哪种方法更快,但是在涉及像.jpeg.html这样的扩展名时,这种方法会更加可靠。

x.replace(/\.[^/.]+$/, "")

19
您可能还希望禁止使用斜杠(/)作为路径分隔符,因此正则表达式为 /.[^/.]+$/。 - gsnedders
1
这适用于任何长度的文件扩展名(.txt或.html或.htaccess),并且还允许文件名包含其他句点(.)字符。它无法处理例如.tar.gz,因为扩展名本身包含一个句点。文件名包含其他句点比文件扩展名更常见。谢谢! - Steve Seeger
7
@Vik,“正确答案”和被采纳的答案是有区别的。被采纳的答案仅仅是对提问者有帮助的答案。 - Steven
6
我认为Windows平台可能会出现问题,因为可能存在反斜杠。因此,正则表达式应该是/.[^/\.]+$/。 - Alex Chuev
2
@ElgsQianChen 这里有一个非常好的工具,可以帮助你回答你的问题 https://regexr.com/ - John Hartsock
显示剩余6条评论

600

Node.js 中,可以通过以下方式获取不带扩展名的文件名。

const path = require('path');
const filename = 'hello.html';
    
path.parse(filename).name;     //=> "hello"
path.parse(filename).ext;      //=> ".html"
path.parse(filename).base; //=> "hello.html"

请查阅 Node.js 文档 以了解更多。


3
这个答案比较局限,仅适用于服务器端的Node。如果您尝试在React代码中使用它,似乎无法导入。 - Charlie
4
如果你想从包括目录的路径中移除扩展名,你可以执行var parsed = path.parse(filename),然后执行path.join(parsed.dir, parsed.name) - Jespertheend
2
另一种可能性是 let base = path.basename( file_path, path.extname( file_path ) ) - bicarlsen

295
如果您知道扩展名的长度,可以使用 x.slice(0, -4)(其中4是扩展名和句点的三个字符)。
如果您不知道长度,则使用正则表达式会是正确的方法。@John Hartsock 参见:regex
如果您不想使用正则表达式,可以尝试这个方法(性能较差):
filename.split('.').slice(0, -1).join('.')

请注意,它将无法处理没有扩展名的文件。


35
这并不是最佳的解决方案,请查看下面的其他解决方案。 - bunjeeb
9
如果你不确定扩展名的长度,请不要使用以下代码:"picture.jpeg".slice(0, -4) -> "picture." - basic6
17
这是一个危险的解决方案,因为你并不真正了解格式的长度。 - rossanmol
如果你知道扩展名的长度,这个假设已经过时了。不要再使用它。 - Alexander
@Alexander 很抱歉回复晚了,但在你知道扩展名长度的情况下,这是一种完全可接受的解决方案,尽管你可能认为这种情况不存在。在我的情况下,我正在过滤所有不以“.js”结尾的文件,所以我不会以任何方式获得不同的扩展名长度。 - OOPS Studio
显示剩余3条评论

139
x.length-4 只考虑到3个字符的扩展名。那如果你有 filename.jpeg 或者 filename.pl 呢?
编辑:
回答一下......是的,如果你总是有一个 .jpg 扩展名,x.length-4 也完全可以使用。
但是,如果您不知道扩展名的长度,任何数量的解决方案都更好/更健壮。 x = x.replace(/\..+$/, ''); 或者 x = x.substring(0, x.lastIndexOf('.')); 或者 x = x.replace(/(.*)\.(.*?)$/, "$1"); 或者(假设文件名只有一个点)
parts = x.match(/[^\.]+/);
x = parts[0];

或(也可以只有一个点)

parts = x.split(".");
x = parts[0];

14
如果有一个文件名,比如“summer.family.jpg”,那么使用split('.')[0]将只返回部分文件名。我建议在答案中删除这个例子,或者明确表示出这个例子存在的问题。@basarat... - Roko C. Buljan
x.split(".") 不应该被视为一个答案。我知道在我的几乎所有文件命名约定中都使用了“.”,例如“survey.controller.js”或“my.family.jpg”。 - Lee Brindley
@tborychowski 当第一个参数为0时,substrsubstring的作用是相同的。请参考:https://dev59.com/f2865IYBdhLWcg3wkfgW - Jeff B
“它适用于这种情况”并不总是等同于“它是正确的实现”:-) substring 的第二个参数是 indexEnd,而 substr 则需要 length,所以在我看来,substring 更适合这里。 - Dziad Borowy
x = x.substring(0, x.lastIndexOf('.')); 这是我的选择。谢谢! - Leonid Zadorozhnykh
显示剩余4条评论

74

我喜欢这个代码,因为它只有一行,不难阅读:

filename.substring(0, filename.lastIndexOf('.')) || filename

2
我认为这个是最好的,因为它非常容易理解。 - Angel

53

你可以尝试利用假设最后一个句点是扩展名分隔符的方法。

var x = 'filename.jpg';
var f = x.substr(0, x.lastIndexOf('.'));

如果文件没有扩展名,它将返回空字符串。使用此函数可以解决该问题。

function removeExtension(filename){
    var lastDotPosition = filename.lastIndexOf(".");
    if (lastDotPosition === -1) return filename;
    else return filename.substr(0, lastDotPosition);
}

警告,如果没有文件名扩展名,则此操作将失败。您将得到一个空字符串。 - Brad
30
这段代码的简化版是:var f = x.substr(0, x.lastIndexOf('.')) || x;。它之所以有效是因为空字符串是假值,所以会返回x。 - Jonathan Rowny
String.prototype.substr()已被弃用,请使用String.prototype.slice()String.prototype.substring()。文档可以在这里找到。 - nCr78

23
在 Node.js 版本 0.12.x 之前: < p > path.basename(filename, path.extname(filename))

当然,在 0.12.x 及更高版本中也适用。

path.parse的答案更简单。 - Dan Dascalescu

16

我不知道这是否是一个有效的选项,但我使用了这个:

name = filename.split(".");
// trimming with pop()
name.pop();
// getting the name with join()
name.join('.'); // we split by '.' and we join by '.' to restore other eventual points.

我知道这不只是一次操作,但至少它应该始终有效!

更新:如果您想要一行代码,请看这里:

(name.split('.').slice(0, -1)).join('.')


1
应该使用name.join('.')而不是name.join('')。你用点号分割,但用逗号连接,所以hello.name.txt返回hello, name - Evil
1
filename.split(".").shift(); - gsaandy

13

即使分隔符不在字符串中,此方法也有效。

String.prototype.beforeLastIndex = function (delimiter) {
    return this.split(delimiter).slice(0,-1).join(delimiter) || this + ""
}

"image".beforeLastIndex(".") // "image"
"image.jpeg".beforeLastIndex(".") // "image"
"image.second.jpeg".beforeLastIndex(".") // "image.second"
"image.second.third.jpeg".beforeLastIndex(".") // "image.second.third"

可以像这样使用一行代码:

var filename = "this.is.a.filename.txt";
console.log(filename.split(".").slice(0,-1).join(".") || filename + "");

编辑:这是一个更有效率的解决方案:

String.prototype.beforeLastIndex = function (delimiter) {
    return this.substr(0,this.lastIndexOf(delimiter)) || this + ""
}

10

另一个一句话:

x.split(".").slice(0, -1).join(".")

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