如何使用 JavaScript 获取文件扩展名?
Posted
技术标签:
【中文标题】如何使用 JavaScript 获取文件扩展名?【英文标题】:How can I get file extensions with JavaScript? 【发布时间】:2010-09-16 11:49:13 【问题描述】:见代码:
var file1 = "50.xsl";
var file2 = "30.doc";
getFileExtension(file1); //returns xsl
getFileExtension(file2); //returns doc
function getFileExtension(filename)
/*TODO*/
【问题讨论】:
【参考方案1】:较新的编辑:自从这个问题最初发布以来,很多事情都发生了变化——wallacer's revised answer 和 VisioN's excellent breakdown 中有很多非常好的信息
编辑:仅仅因为这是公认的答案; wallacer's answer 确实好很多:
return filename.split('.').pop();
我的旧答案:
return /[^.]+$/.exec(filename);
应该这样做。
编辑:为了回应 PhiLho 的评论,请使用如下内容:
return (/[.]/.exec(filename)) ? /[^.]+$/.exec(filename) : undefined;
【讨论】:
执行两次正则表达式不是很贵吗? 下面高度评价的答案要好得多。 不幸的是,对于 file 和 .htaccess 等名称,这两种解决方案都失败了。 所有可能的情况处理如下:return filename.split(".").slice(1).pop() || ""; @JustAndrei 仍然不是全部 :) 对于纯文件名(basename?),而不是路径,出于实际原因,我认为应该是return filename.substring(0,1) === '.' ? '' : filename.split('.').slice(1).pop() || '';
这照顾 .file
(Unix 隐藏,我相信)也是一种文件。也就是说,如果您想将其保留为单线,这对我来说有点乱。【参考方案2】:
return filename.split('.').pop();
编辑:
这是另一种我认为更有效的非正则表达式解决方案:
return filename.substring(filename.lastIndexOf('.')+1, filename.length) || filename;
下面的VisioN's answer 可以更好地处理一些极端情况,尤其是没有扩展名的文件(包括.htaccess
等)。
它的性能非常好,并且当点之前没有点或没有字符串时,通过返回""
而不是完整的字符串,以一种可以说更好的方式处理极端情况。这是一个精心设计的解决方案,尽管很难阅读。将它粘贴到您的助手库中并使用它。
旧编辑:
如果您要遇到没有扩展名的文件或没有扩展名的隐藏文件(请参阅 VisioN 对上面汤姆的回答的评论),那么更安全的实施方式将是这样的
var a = filename.split(".");
if( a.length === 1 || ( a[0] === "" && a.length === 2 ) )
return "";
return a.pop(); // feel free to tack .toLowerCase() here if you want
如果a.length
为1,则它是一个没有扩展名的可见文件,即。 文件
如果a[0] === ""
和a.length === 2
它是一个没有扩展名的隐藏文件,即。 .htaccess
这应该可以解决稍微复杂一些的问题。在性能方面,我认为这个解决方案在大多数浏览器中是a little slower than regex。然而,对于最常见的目的,这段代码应该是完全可用的。
【讨论】:
我无法评价性能,但这个肯定看起来很干净!我正在使用它。 +1 但在这种情况下,文件名看起来像 filname.tes.test.jpg。请考虑输出。我希望它是假的。 在这种情况下,输出为“jpg” 太棒了!非常感谢。很高兴看到不使用正则表达式的解决方案;我已经用 php 完成了这个,它只使用了几个函数。 +1 @wallacer:如果filename
实际上没有扩展名会怎样?这不会简单地返回基本文件名,这会有点糟糕吗?【参考方案3】:
以下解决方案 fast 和 short 足以用于批量操作并节省额外字节:
return fname.slice((fname.lastIndexOf(".") - 1 >>> 0) + 2);
这是另一种单行非正则表达式通用解决方案:
return fname.slice((Math.max(0, fname.lastIndexOf(".")) || Infinity) + 1);
对于没有扩展名的名称(例如 myfile)或以 .
点开头的名称(例如 .htaccess),两者都可以正常工作:
"" --> ""
"name" --> ""
"name.txt" --> "txt"
".htpasswd" --> ""
"name.with.many.dots.myext" --> "myext"
如果您关心速度,您可以运行 benchmark 并检查提供的解决方案是最快的,而短的解决方案非常快:
短款的工作原理:
String.lastIndexOf
方法返回给定字符串(即fname
)中子字符串(即"."
)的最后位置。如果未找到子字符串,则方法返回 -1
。
文件名中“不可接受”的点位置是-1
和0
,它们分别指的是没有扩展名的名称(例如"name"
)和以点开头的名称(例如".htaccess"
)。
Zero-fill right shift operator (>>>
) 如果与零一起使用会影响将-1
转换为4294967295
和-2
到4294967294
的负数,这对于在边缘情况下保持文件名不变很有用(这里有点技巧)。
String.prototype.slice
从按所述计算的位置提取文件名的一部分。如果位置编号大于字符串的长度,方法返回""
。
如果您想要以相同方式工作的更清晰的解决方案(加上对完整路径的额外支持),请查看以下扩展版本。此解决方案将比以前的单行方法慢,但更容易理解。
function getExtension(path)
var basename = path.split(/[\\/]/).pop(), // extract file name from full path ...
// (supports `\\` and `/` separators)
pos = basename.lastIndexOf("."); // get last position of `.`
if (basename === "" || pos < 1) // if file name is empty or ...
return ""; // `.` not found (-1) or comes first (0)
return basename.slice(pos + 1); // extract extension ignoring `.`
console.log( getExtension("/path/to/file.ext") );
// >> "ext"
所有三种变体都可以在客户端的任何 Web 浏览器中运行,也可以在服务器端的 NodeJS 代码中使用。
【讨论】:
@mrbrdo 根据问题的要求,此方法不应仅适用于文件名的完整路径。在投反对票之前仔细阅读问题。 他从来没有明确说过,如果它在路径上工作,显然它会更有用 为什么要不遗余力地优化这样一行微不足道的代码呢?波浪号和位移运算符在 javascript 中很少见,我无法支持这样的答案。如果需要 5 个要点来解释 1 行代码的工作原理,最好重写代码,使其实际上可以理解。 这一行的速度在任何应用程序中都不会产生明显的差异。 Bitwise 很少使用,以至于 JSLint 和 JSHint 等流行的 linter 警告不要使用它们。对这种逻辑的性能和紧凑性的执着降低了代码的质量;如果代码需要“额外调查”,我认为它“不好”。 @Jackson 考虑到这是一个为一个问题提供多种解决方案的网站,拥有一个优化性能的解决方案绝不是一件坏事。您的陈述“在任何应用程序中都不会产生明显的差异”完全基于您可能使用的可能应用程序的狭窄范围。除此之外,它可能会为研究问题的人提供一种学习体验,他们可以在其中优化一些他们需要为正在编写的计算密集型应用程序编写其他代码。【参考方案4】:function getFileExtension(filename)
var ext = /^.+\.([^.]+)$/.exec(filename);
return ext == null ? "" : ext[1];
经过测试
"a.b" (=> "b")
"a" (=> "")
".hidden" (=> "")
"" (=> "")
null (=> "")
还有
"a.b.c.d" (=> "d")
".a.b" (=> "b")
"a..b" (=> "b")
【讨论】:
让它在 IE 中工作: var pattern = "^.+\\.([^.]+)$"; var ext = new RegExp(pattern);【参考方案5】:function getExt(filename)
var ext = filename.split('.').pop();
if(ext == filename) return "";
return ext;
【讨论】:
返回(ext===文件名)? '' : 分机;【参考方案6】:path
模块中有一个标准库函数:
import path from 'path';
console.log(path.extname('abc.txt'));
输出:
.txt
所以,如果你只想要格式:
path.extname('abc.txt').slice(1) // 'txt'
如果没有扩展,那么函数将返回一个空字符串:
path.extname('abc') // ''
如果您使用的是 Node,那么 path
是内置的。如果你的目标是浏览器,那么 Webpack 将为你捆绑一个 path
实现。如果您的目标浏览器没有 Webpack,那么您可以手动包含 path-browserify。
没有理由进行字符串拆分或正则表达式。
【讨论】:
谁说过节点? 您不使用拆分或正则表达式的论点是包含插件或将应用程序与节点捆绑在一起,这是一项琐碎任务的最佳答案 @ShannonHochkins 大多数时候你都已经设置好了这些东西 @AndreiDraganescu 我不打算让它居高临下,所以已经淡化了。 效果很好。 webpack 已经非常普遍地用于针对浏览器的客户端开发。这是多年前确立的。使用 node 的服务器端开发人员已经内置了这个。为什么要重复已经为您完成的工作?我不会为此使用 webpack,但如果你有它,请使用它。【参考方案7】:var extension = fileName.substring(fileName.lastIndexOf('.')+1);
【讨论】:
【参考方案8】:如果您正在处理网页网址,您可以使用:
function getExt(filepath)
return filepath.split("?")[0].split("#")[0].split('.').pop();
getExt("../js/logic.v2.min.js") // js
getExt("http://example.net/site/page.php?id=16548") // php
getExt("http://example.net/site/page.html#welcome.to.me") // html
getExt("c:\\logs\\yesterday.log"); // log
演示:https://jsfiddle.net/squadjot/q5ard4fj/
【讨论】:
我真的很喜欢你的解决方案。它用这么少做这么多。我会用它。【参考方案9】:var parts = filename.split('.');
return parts[parts.length-1];
【讨论】:
这会导致在文件命名为“2021.06.28 - MyReport.csv”时捕获错误的扩展名【参考方案10】:function file_get_ext(filename)
return typeof filename != "undefined" ? filename.substring(filename.lastIndexOf(".")+1, filename.length).toLowerCase() : false;
【讨论】:
【参考方案11】:代码
/**
* Extract file extension from URL.
* @param String url
* @returns String File extension or empty string if no extension is present.
*/
var getFileExtension = function (url)
"use strict";
if (url === null)
return "";
var index = url.lastIndexOf("/");
if (index !== -1)
url = url.substring(index + 1); // Keep path without its segments
index = url.indexOf("?");
if (index !== -1)
url = url.substring(0, index); // Remove query
index = url.indexOf("#");
if (index !== -1)
url = url.substring(0, index); // Remove fragment
index = url.lastIndexOf(".");
return index !== -1
? url.substring(index + 1) // Only keep file extension
: ""; // No extension found
;
测试
请注意,在没有查询的情况下,片段可能仍然存在。
"https://www.example.com:8080/segment1/segment2/page.html?foo=bar#fragment" --> "html"
"https://www.example.com:8080/segment1/segment2/page.html#fragment" --> "html"
"https://www.example.com:8080/segment1/segment2/.htaccess?foo=bar#fragment" --> "htaccess"
"https://www.example.com:8080/segment1/segment2/page?foo=bar#fragment" --> ""
"https://www.example.com:8080/segment1/segment2/?foo=bar#fragment" --> ""
"" --> ""
null --> ""
"a.b.c.d" --> "d"
".a.b" --> "b"
".a.b." --> ""
"a...b" --> "b"
"..." --> ""
JSLint
0 个警告。
【讨论】:
如果您在末尾引入另一个斜杠(例如编码的东西),则不起作用,即:“example.com:8080/segment1/segment2/page.html?enc=abc/def” 【参考方案12】:快速且可正确使用路径
(filename.match(/[^\\\/]\.([^.\\\/]+)$/) || [null]).pop()
一些极端情况
/path/.htaccess => null
/dir.with.dot/file => null
使用 split 的解决方案速度很慢,而使用 lastIndexOf 的解决方案无法处理边缘情况。
【讨论】:
你的意思是什么边缘情况?请在此处参考我的解决方案:***.com/a/12900504/1249581。它在所有情况下都能正常工作,并且比任何正则表达式都要快。 我已经列出了边缘情况。而且您的解决方案无法正确处理它们。就像我已经写过的一样,试试“/dir.with.dot/file”。您的代码返回“点/文件”,这是非常错误的。 没有人请求解析路径。问题是关于从文件名中提取扩展名。 就像我已经告诉过你的那样,从来没有明确说过,处理路径的解决方案显然更有用。除了提出问题的人之外,关于 SO 的问题的答案应该对其他人有用。我真的不认为处理输入超集的解决方案应该被否决。 否决票是因为使用带有.exec()
的全局变量。你的代码会更好(filename.match(/[^\\/]\.([^\\/.]+)$/) || [null]).pop()
。【参考方案13】:
// 获取文件后缀名
function getFileExtension(file)
var regexp = /\.([0-9a-z]+)(?:[\?#]|$)/i;
var extension = file.match(regexp);
return extension && extension[1];
console.log(getFileExtension("https://www.example.com:8080/path/name/foo"));
console.log(getFileExtension("https://www.example.com:8080/path/name/foo.BAR"));
console.log(getFileExtension("https://www.example.com:8080/path/name/.quz/foo.bar?key=value#fragment"));
console.log(getFileExtension("https://www.example.com:8080/path/name/.quz.bar?key=value#fragment"));
【讨论】:
【参考方案14】:我只是想分享这个。
fileName.slice(fileName.lastIndexOf('.'))
虽然这有一个缺点,即没有扩展名的文件将返回最后一个字符串。 但如果你这样做,这将解决所有问题:
function getExtention(fileName)
var i = fileName.lastIndexOf('.');
if(i === -1 ) return false;
return fileName.slice(i)
【讨论】:
据我记得slice
方法是指数组而不是字符串。对于字符串 substr
或 substring
将起作用。
@VisioN 但我想你应该知道有 String.prototype.slice
和 Array.prototype.slice
所以这两种工作方式都是一种方法
啊,是的。你说的对。完全忘记了这个方法。我的错。【参考方案15】:
我相信将来有人可以并且将会缩小和/或优化我的代码。但是,截至 现在,我 200% 确信我的代码适用于每一种独特的情况(例如,仅使用 文件名,使用 relative em>、root-relative 和 absolute URL,带有 fragment #
标签,带有 query @987654324 @ 字符串,以及您可能决定扔给它的任何其他内容),完美无瑕,并且具有精确度。
如需证明,请访问:https://projects.jamesandersonjr.com/web/js_projects/get_file_extension_test.php
这是 JSFiddle:https://jsfiddle.net/JamesAndersonJr/ffcdd5z3/
不要过于自信,也不要自吹自擂,但我还没有看到 任何 用于此任务的代码块(找到 '正确' 文件扩展名,在一组不同的function
输入参数中),效果和这个一样。
注意:按照设计,如果给定的输入字符串不存在文件扩展名,它只会返回一个空白字符串""
,而不是错误,也不是错误消息。
需要两个参数:
字符串: fileNameOrURL (不言自明)
布尔值: showUnixDotFiles(是否显示以点“.”开头的文件)
注意(2):如果您喜欢我的代码,请务必将其添加到您的 js 库和/或 repo 中,因为我努力完善它,这将是一种耻辱去浪费。所以,事不宜迟,这里是:
function getFileExtension(fileNameOrURL, showUnixDotFiles)
/* First, let's declare some preliminary variables we'll need later on. */
var fileName;
var fileExt;
/* Now we'll create a hidden anchor ('a') element (Note: No need to append this element to the document). */
var hiddenLink = document.createElement('a');
/* Just for fun, we'll add a CSS attribute of [ style.display = "none" ]. Remember: You can never be too sure! */
hiddenLink.style.display = "none";
/* Set the 'href' attribute of the hidden link we just created, to the 'fileNameOrURL' argument received by this function. */
hiddenLink.setAttribute('href', fileNameOrURL);
/* Now, let's take advantage of the browser's built-in parser, to remove elements from the original 'fileNameOrURL' argument received by this function, without actually modifying our newly created hidden 'anchor' element.*/
fileNameOrURL = fileNameOrURL.replace(hiddenLink.protocol, ""); /* First, let's strip out the protocol, if there is one. */
fileNameOrURL = fileNameOrURL.replace(hiddenLink.hostname, ""); /* Now, we'll strip out the host-name (i.e. domain-name) if there is one. */
fileNameOrURL = fileNameOrURL.replace(":" + hiddenLink.port, ""); /* Now finally, we'll strip out the port number, if there is one (Kinda overkill though ;-)). */
/* Now, we're ready to finish processing the 'fileNameOrURL' variable by removing unnecessary parts, to isolate the file name. */
/* Operations for working with [relative, root-relative, and absolute] URL's ONLY [BEGIN] */
/* Break the possible URL at the [ '?' ] and take first part, to shave of the entire query string ( everything after the '?'), if it exist. */
fileNameOrURL = fileNameOrURL.split('?')[0];
/* Sometimes URL's don't have query's, but DO have a fragment [ # ](i.e 'reference anchor'), so we should also do the same for the fragment tag [ # ]. */
fileNameOrURL = fileNameOrURL.split('#')[0];
/* Now that we have just the URL 'ALONE', Let's remove everything to the last slash in URL, to isolate the file name. */
fileNameOrURL = fileNameOrURL.substr(1 + fileNameOrURL.lastIndexOf("/"));
/* Operations for working with [relative, root-relative, and absolute] URL's ONLY [END] */
/* Now, 'fileNameOrURL' should just be 'fileName' */
fileName = fileNameOrURL;
/* Now, we check if we should show UNIX dot-files, or not. This should be either 'true' or 'false'. */
if ( showUnixDotFiles == false )
/* If not ('false'), we should check if the filename starts with a period (indicating it's a UNIX dot-file). */
if ( fileName.startsWith(".") )
/* If so, we return a blank string to the function caller. Our job here, is done! */
return "";
;
;
/* Now, let's get everything after the period in the filename (i.e. the correct 'file extension'). */
fileExt = fileName.substr(1 + fileName.lastIndexOf("."));
/* Now that we've discovered the correct file extension, let's return it to the function caller. */
return fileExt;
;
享受吧!不客气!:
【讨论】:
太棒了。谢谢!【参考方案16】:"one-liner" 使用reduce
和array destructuring 获取文件名和扩展名:
var str = "filename.with_dot.png";
var [filename, extension] = str.split('.').reduce((acc, val, i, arr) => (i == arr.length - 1) ? [acc[0].substring(1), val] : [[acc[0], val].join('.')], [])
console.log(filename, extension);
更好的缩进:
var str = "filename.with_dot.png";
var [filename, extension] = str.split('.')
.reduce((acc, val, i, arr) => (i == arr.length - 1)
? [acc[0].substring(1), val]
: [[acc[0], val].join('.')], [])
console.log(filename, extension);
//
// "filename": "filename.with_dot",
// "extension": "png"
//
【讨论】:
您可以使用 babel / typescript / polyfills 来弥补 IE 11 缺少的 ES7+ 功能【参考方案17】:还有一种使用 ES6 解构的简单方法:
const path = 'hello.world.txt'
const [extension, ...nameParts] = path.split('.').reverse();
console.log('extension:', extension);
【讨论】:
【参考方案18】:function extension(fname)
var pos = fname.lastIndexOf(".");
var strlen = fname.length;
if (pos != -1 && strlen != pos + 1)
var ext = fname.split(".");
var len = ext.length;
var extension = ext[len - 1].toLowerCase();
else
extension = "No extension found";
return extension;
//用法
扩展名('file.jpeg')
始终返回扩展小写,以便您可以在字段更改时检查它 适用于:
文件.JpEg
文件(无扩展名)
文件。 (无扩展名)
【讨论】:
【参考方案19】:试试这个:
function getFileExtension(filename)
var fileinput = document.getElementById(filename);
if (!fileinput)
return "";
var filename = fileinput.value;
if (filename.length == 0)
return "";
var dot = filename.lastIndexOf(".");
if (dot == -1)
return "";
var extension = filename.substr(dot, filename.length);
return extension;
【讨论】:
【参考方案20】:如果你正在寻找一个特定的扩展并且知道它的长度,你可以使用substr:
var file1 = "50.xsl";
if (file1.substr(-4) == '.xsl')
// do something
JavaScript 参考: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/substr
【讨论】:
美丽源于简约。这是所有答案中最聪明、更优雅、更有效的答案。我总是使用 String.substr(-3) 或 String.substr(-4) 在基于 Windows 的系统上获取扩展。为什么有人要为此使用正则表达式和疯狂循环。 @asiby 这种解决方案是太空火箭发射后坠毁的主要原因。【参考方案21】:这个简单的解决方案
function extension(filename)
var r = /.+\.(.+)$/.exec(filename);
return r ? r[1] : null;
测试
/* tests */
test('cat.gif', 'gif');
test('main.c', 'c');
test('file.with.multiple.dots.zip', 'zip');
test('.htaccess', null);
test('noextension.', null);
test('noextension', null);
test('', null);
// test utility function
function test(input, expect)
var result = extension(input);
if (result === expect)
console.log(result, input);
else
console.error(result, input);
function extension(filename)
var r = /.+\.(.+)$/.exec(filename);
return r ? r[1] : null;
【讨论】:
【参考方案22】:return filename.replace(/\.([a-zA-Z0-9]+)$/, "$1");
编辑:奇怪(或者可能不是)替换方法的第二个参数中的$1
似乎不起作用......对不起。
【讨论】:
它工作得很好,但是你错过了你必须删除字符串的所有其他内容:return filename.replace(/^.*?\.([a-zA-Z0 -9]+)$/, "$1");【参考方案23】:我刚刚意识到仅仅对 p4bl0 的回答发表评论是不够的,尽管 Tom 的回答清楚地解决了问题:
return filename.replace(/^.*?\.([a-zA-Z0-9]+)$/, "$1");
【讨论】:
【参考方案24】:对于大多数应用程序,一个简单的脚本,例如
return /[^.]+$/.exec(filename);
可以正常工作(由 Tom 提供)。然而,这并不是万无一失的。如果提供以下文件名则不起作用:
image.jpg?foo=bar
这可能有点矫枉过正,但我建议使用 url 解析器,例如 this one,以避免由于不可预测的文件名而导致失败。
使用该特定函数,您可以获得如下文件名:
var trueFileName = parse_url('image.jpg?foo=bar').file;
这将输出不带 url 变量的“image.jpg”。然后你就可以随意获取文件扩展名了。
【讨论】:
【参考方案25】:function func()
var val = document.frm.filename.value;
var arr = val.split(".");
alert(arr[arr.length - 1]);
var arr1 = val.split("\\");
alert(arr1[arr1.length - 2]);
if (arr[1] == "gif" || arr[1] == "bmp" || arr[1] == "jpeg")
alert("this is an image file ");
else
alert("this is not an image file");
【讨论】:
【参考方案26】:我迟到了很多个月,但为了简单起见,我使用了这样的东西
var fileName = "I.Am.FileName.docx";
var nameLen = fileName.length;
var lastDotPos = fileName.lastIndexOf(".");
var fileNameSub = false;
if(lastDotPos === -1)
fileNameSub = false;
else
//Remove +1 if you want the "." left too
fileNameSub = fileName.substr(lastDotPos + 1, nameLen);
document.getElementById("showInMe").innerHTML = fileNameSub;
<div id="showInMe"></div>
【讨论】:
【参考方案27】:一种单行解决方案,还可以考虑查询参数和 url 中的任何字符。
string.match(/(.*)\??/i).shift().replace(/\?.*/, '').split('.').pop()
// Example
// some.url.com/with.in/&ot.s/files/file.jpg?spec=1&.ext=jpg
// jpg
【讨论】:
(1) 如果文件没有扩展名,这仍然会返回文件名。 (2) 如果 URL 中有片段,但没有查询(例如page.html#fragment
),这将返回文件扩展名和片段。【参考方案28】:
fetchFileExtention(fileName)
return fileName.slice((fileName.lastIndexOf(".") - 1 >>> 0) + 2);
【讨论】:
虽然这段代码 sn-p 可以解决问题,including an explanation 确实有助于提高您的帖子质量。请记住,您是在为将来的读者回答问题,而这些人可能不知道您提出代码建议的原因。【参考方案29】:Wallacer 的回答很好,但需要再检查一次。
如果文件没有扩展名,它将使用文件名作为扩展名,这是不好的。
试试这个:
return ( filename.indexOf('.') > 0 ) ? filename.split('.').pop().toLowerCase() : 'undefined';
【讨论】:
【参考方案30】:别忘了有些文件可以没有扩展名,所以:
var parts = filename.split('.');
return (parts.length > 1) ? parts.pop() : '';
【讨论】:
以上是关于如何使用 JavaScript 获取文件扩展名?的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 Javascript 获取未知文件路径 - 扩展路径?
如何使用 package.json 脚本复制具有特定文件扩展名的文件