717

See code:

var file1 = "50.xsl";
var file2 = "30.doc";
getFileExtension(file1); //returns xsl
getFileExtension(file2); //returns doc

function getFileExtension(filename) {
    /*TODO*/
}
Ghoul Fool
  • 6,249
  • 10
  • 67
  • 125
Sergio del Amo
  • 76,835
  • 68
  • 152
  • 179

36 Answers36

1139

Newer Edit: Lots of things have changed since this question was initially posted - there's a lot of really good information in wallacer's revised answer as well as VisioN's excellent breakdown


Edit: Just because this is the accepted answer; wallacer's answer is indeed much better:

return filename.split('.').pop();

My old answer:

return /[^.]+$/.exec(filename);

Should do it.

Edit: In response to PhiLho's comment, use something like:

return (/[.]/.exec(filename)) ? /[^.]+$/.exec(filename) : undefined;
Community
  • 1
  • 1
Tom
  • 5,835
  • 4
  • 25
  • 30
  • 4
    Isn't it expensive to exec the regex twice? – Andrew Hedges Oct 11 '08 at 07:39
  • 2
    Unfortunately both solutions fail for names like *file* and *.htaccess*. – VisioN Oct 15 '12 at 17:19
  • 4
    All possible cases are processed as follows: return filename.split(".").slice(1).pop() || ""; – JustAndrei Apr 10 '14 at 12:59
  • 1
    @JustAndrei Still not all :) For pure file name (basename?), not a path, for practical reasons, I think it should be `return filename.substring(0,1) === '.' ? '' : filename.split('.').slice(1).pop() || '';` This takes care of `.file` (Unix hidden, I believe) kind of files too. That is if you want to keep it as a one-liner, which is a bit messy to my taste. – kooker Jun 21 '14 at 04:00
  • 1
    On a filename like path/to/file.png?v1.4.1 it will not work! – dude Sep 01 '15 at 07:04
  • 1
    Bad solution. As multiplte users already stated, returns file name if it has no extension. – JayC667 Jul 31 '18 at 13:13
  • there is a small problem with split. If you uses (for whatever reason) jquery it will becomes slow due the fact that jquery try to handle the split() byself. In this case the other one liner answers will be faster. E.g. use a one liner without split. – Thomas Ludewig Jan 28 '21 at 13:59
  • What if the file is e.g. a `png` but the filename is `something` instead of `something.png` ? – Kawd May 26 '22 at 17:37
  • This solution has a bug and should not be used, as it will return the full filename if the extension is missing – John Miller Jul 20 '23 at 17:02
1092
return filename.split('.').pop();

Edit:

This is another non-regex solution that I think is more efficient:

return filename.substring(filename.lastIndexOf('.')+1, filename.length) || filename;

There are some corner cases that are better handled by VisioN's answer below, particularly files with no extension (.htaccess etc included).

It's very performant, and handles corner cases in an arguably better way by returning "" instead of the full string when there's no dot or no string before the dot. It's a very well crafted solution, albeit tough to read. Stick it in your helpers lib and just use it.

Old Edit:

A safer implementation if you're going to run into files with no extension, or hidden files with no extension (see VisioN's comment to Tom's answer above) would be something along these lines

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

If a.length is one, it's a visible file with no extension ie. file

If a[0] === "" and a.length === 2 it's a hidden file with no extension ie. .htaccess

This should clear up issues with the slightly more complex cases. In terms of performance, I think this solution is a little slower than regex in most browsers. However, for most common purposes this code should be perfectly usable.

Halo
  • 1,730
  • 1
  • 8
  • 31
wallacer
  • 12,855
  • 3
  • 27
  • 45
  • 7
    but in this case the file name looks like filname.tes.test.jpg. Kindly consider the output. I hope it will be false. – Fero Jul 02 '10 at 09:56
  • 22
    in that case the output is "jpg" – wallacer Sep 28 '10 at 21:53
  • 3
    @wallacer: What happens if `filename` actually doesn't have an extension? Wouldn't this simply return the base filename, which would be kinda bad? – Nicol Bolas Oct 26 '11 at 20:33
  • Might consider tossing on a .toLowerCase() to the end of that. – MrBojangles Oct 29 '11 at 00:09
  • @NicolBolas yes it would. This was just the easiest non-regex implementation I could think of in about 5 seconds about 2 years ago. Seems to be helping people though :) It should definitely be jazzed up with a bit of error handling, lower casing etc. for actual use. – wallacer Nov 16 '11 at 00:38
  • 1
    There is a typo in the Edit section. Should be `var a = filename.split(".");` – GEMI Sep 30 '13 at 10:21
  • does not work for "/home/user/.app/config" (even the "improved" version). – mrbrdo Oct 13 '13 at 15:47
  • @mrbrdo True story - I guess filename.split('/').pop().split('.').pop() would handle absolute paths. Good catch! ;) – wallacer Oct 17 '13 at 16:54
  • I've put up a solution with a regexp that handles that case as well. I think regexps are an obvious solution for this problem since it's a moderately complex string parsing issue. – mrbrdo Oct 18 '13 at 15:35
  • Yes, with my solution I'm not suggesting that regex isn't a good way to go. This was years ago, and there was only a bunch of semi-complicated regexp's and thought I'd throw out a simple non regex solution that covers simple cases. – wallacer Oct 18 '13 at 21:38
  • @wallacer Unfortunately your newest solution doesn't work well with files starting with dot, e.g. `.htaccess` and with files having no extension at all. That was the main reason why I used a bit more complicated logic in my answer. – VisioN Jun 03 '15 at 15:27
  • @VisioN Right, thanks for pointing that out! I updated my answer recommending your, brilliant solution. – wallacer Jun 03 '15 at 17:57
  • On a filename like path/to/file.png?v1.4.1 it will not work! – dude Sep 01 '15 at 07:05
  • @julmot what are you expecting the extension of that file to be? .png? Are you trying to use a query string, because that would look more like file.png?v=1.4.1. If you're storing files with names like "file.png?v1.4.1" and expect your filesystem to treat them as .png files, things aren't going to go well for you my friend. Yes, if you have some weird use case that's outside the realm of normality, then sure, this algorithm doesn't read your mind and extract .png from within the middle of a string. It's pretty clear what it does. If it's not what you need, use something else. – wallacer Sep 01 '15 at 21:52
  • If you are building a new filename and want to extract the extension to stick it on another basename, then it helps to have the "." but only if an extension exists. So change the 2 to a 1 and you can do newname = newbase + fname.substr((~-fname.lastIndexOf(".") >>> 0) + 1); No need to mess around adding a dot conditionally. – Julian Mann Feb 11 '16 at 01:51
  • This won't work for paths. For example `'http:://someurl.com/file.png?user_token=some.hash.with.dot'` – Alvaro Jul 27 '20 at 12:02
387

The following solution is fast and short enough to use in bulk operations and save extra bytes:

 return fname.slice((fname.lastIndexOf(".") - 1 >>> 0) + 2);

Here is another one-line non-regexp universal solution:

 return fname.slice((Math.max(0, fname.lastIndexOf(".")) || Infinity) + 1);

Both work correctly with names having no extension (e.g. myfile) or starting with . dot (e.g. .htaccess):

 ""                            -->   ""
 "name"                        -->   ""
 "name.txt"                    -->   "txt"
 ".htpasswd"                   -->   ""
 "name.with.many.dots.myext"   -->   "myext"

If you care about the speed you may run the benchmark and check that the provided solutions are the fastest, while the short one is tremendously fast:

Speed comparison

How the short one works:

  1. String.lastIndexOf method returns the last position of the substring (i.e. ".") in the given string (i.e. fname). If the substring is not found method returns -1.
  2. The "unacceptable" positions of dot in the filename are -1 and 0, which respectively refer to names with no extension (e.g. "name") and to names that start with dot (e.g. ".htaccess").
  3. Zero-fill right shift operator (>>>) if used with zero affects negative numbers transforming -1 to 4294967295 and -2 to 4294967294, which is useful for remaining the filename unchanged in the edge cases (sort of a trick here).
  4. String.prototype.slice extracts the part of the filename from the position that was calculated as described. If the position number is more than the length of the string method returns "".

If you want more clear solution which will work in the same way (plus with extra support of full path), check the following extended version. This solution will be slower than previous one-liners but is much easier to understand.

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"

All three variants should work in any web browser on the client side and can be used in the server side NodeJS code as well.

PedroZorus
  • 661
  • 1
  • 6
  • 21
VisioN
  • 143,310
  • 32
  • 282
  • 281
  • "fname.substr((~-fname.lastIndexOf(".") >>> 0) + 2)" gives a wrong value for ".htaccess". – Benny Code Oct 09 '13 at 10:35
  • @BennyNeugebauer What is wrong in your case? It gives `""` since filename that starts with dot (like `.htaccess` or `.htpasswd`) doesn't have extension. – VisioN Oct 09 '13 at 10:45
  • I would expect the extension to be "htaccess"? But that is a matter of opinion. You're right! I just wanted to point out. :) – Benny Code Oct 09 '13 at 10:49
  • @BennyNeugebauer Technically `.htaccess` doesn't have an extension, since [this *is* an extension itself](http://www.javascriptkit.com/howto/htaccess.shtml). This convention is followed by many libraries and programming languages. For example, in Python when you do `os.path.splitext('/path/to/.htaccess')` it returns `""` as an extension [ignoring leading dot](http://hg.python.org/cpython/file/5c8b6e03ebfe/Lib/genericpath.py#l78), considering such name as [a filename with no extension](https://mail.python.org/pipermail/python-dev/2007-March/071756.html). – VisioN Oct 09 '13 at 11:10
  • 3
    @BennyNeugebauer However if you need to exclude this rule just use `fname.substr((fname.lastIndexOf(".") >>> 0) + 1)` instead :) – VisioN Oct 09 '13 at 11:15
  • 6
    Does not work. "/home/user/.app/config" returns "app/config", which is totally wrong. – mrbrdo Oct 13 '13 at 15:45
  • 47
    @mrbrdo This method is not supposed to work with full path only with filenames, as requested by the question. Read question carefully before downvoting. – VisioN Oct 13 '13 at 15:55
  • 7
    he never explicitly said that, and obivously it makes it more useful if it works on paths – mrbrdo Oct 18 '13 at 15:29
  • What about double extensions, like `.tar.gz` ? – Slava Feb 20 '16 at 21:22
  • 1
    @Alph.Dev I doubt you can find any valid algorithm to differentiate all types of extensions without having some kind of a database to check against. Also, to my understanding, `.tar.gz` is not an extension itself, since extension is `.gz` for GZIP'ed file with extension `.tar`, which is a TAR archive. – VisioN Feb 21 '16 at 00:57
  • 1
    I think `str.length` would also work in place of `Infinity`. nice answer btw – Ahmad Sep 22 '20 at 10:14
  • 2
    I tested the _one-line non-regexp universal solution_ and it works (unlike some other answers) with all my tests: `const t = ['./asdf.mz', '/asdf/qwer.maz', 'asdf.mm', 'sdf/qwer.ww', './.asdf.mz', '/asdf/.qwer.maz', '.asdf.mm', 'sdf/.qwer.ww', './asdf', '/adsf/qwer', 'asdf', 'sdf/qewr', './.asdf', '/adsf/.qwer', '.asdf', 'sdf/.qewr']`. I tested it like this: ```t.forEach(file => {const filename = file.match(/[^\/]+$/g)?.[0]; console.log(`${file} : ${filename.slice((Math.max(0, filename.lastIndexOf(".")) || Infinity) + 1)}`)})```. – tukusejssirs Aug 06 '22 at 09:14
42
function getFileExtension(filename)
{
  var ext = /^.+\.([^.]+)$/.exec(filename);
  return ext == null ? "" : ext[1];
}

Tested with

"a.b"     (=> "b") 
"a"       (=> "") 
".hidden" (=> "") 
""        (=> "") 
null      (=> "")  

Also

"a.b.c.d" (=> "d")
".a.b"    (=> "b")
"a..b"    (=> "b")
zangw
  • 43,869
  • 19
  • 177
  • 214
PhiLho
  • 40,535
  • 6
  • 96
  • 134
34

There is a standard library function for this in the path module:

import path from 'path';

console.log(path.extname('abc.txt'));

Output:

.txt

So, if you only want the format:

path.extname('abc.txt').slice(1) // 'txt'

If there is no extension, then the function will return an empty string:

path.extname('abc') // ''

If you are using Node, then path is built-in. If you are targetting the browser, then Webpack will bundle a path implementation for you. If you are targetting the browser without Webpack, then you can include path-browserify manually.

There is no reason to do string splitting or regex.

sdgfsdh
  • 33,689
  • 26
  • 132
  • 245
  • Your argument for not using splitting or regular expressions is to include plugin or bundle the application with node, it's an over the top answer for a menial task – Shannon Hochkins Apr 12 '19 at 05:47
  • 1
    @ShannonHochkins most of the time you have these things set up anyway – sdgfsdh Sep 26 '19 at 16:43
  • 1
    Works well. webpack is very commonly already in place with client side development targeting browsers. This got established years ago. A server side developer working with node already has this built-in. Why duplicate the work already done for you? I would not use webpack just for this but if you have it use it. – wheredidthatnamecomefrom Dec 22 '21 at 22:26
24
function getExt(filename)
{
    var ext = filename.split('.').pop();
    if(ext == filename) return "";
    return ext;
}
Dima
  • 568
  • 4
  • 7
18
var extension = fileName.substring(fileName.lastIndexOf('.')+1);
Pono
  • 11,298
  • 9
  • 53
  • 70
14

If you are dealing with web urls, you can use:

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

Demo: https://jsfiddle.net/squadjot/q5ard4fj/

Jakob Sternberg
  • 1,758
  • 14
  • 12
9
var parts = filename.split('.');
return parts[parts.length-1];
Randy Sugianto 'Yuku'
  • 71,383
  • 57
  • 178
  • 228
  • This would result in a wrong extension captured when files are named something like: "2021.06.28 - MyReport.csv" – mrbitzilla Jun 28 '21 at 20:32
8
function file_get_ext(filename)
    {
    return typeof filename != "undefined" ? filename.substring(filename.lastIndexOf(".")+1, filename.length).toLowerCase() : false;
    }
Joe Scylla
  • 701
  • 3
  • 5
8

Code

/**
 * 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
};

Test

Notice that in the absence of a query, the fragment might still be present.

"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 Warnings.

Jack
  • 1,881
  • 24
  • 29
  • Doesn't work if you have another slash introduced at the end like something encoded, i.e. this: "example.com:8080/segment1/segment2/page.html?enc=abc/def" – Jester Dec 04 '20 at 18:58
7

Fast and works correctly with paths

(filename.match(/[^\\\/]\.([^.\\\/]+)$/) || [null]).pop()

Some edge cases

/path/.htaccess => null
/dir.with.dot/file => null

Solutions using split are slow and solutions with lastIndexOf don't handle edge cases.

mrbrdo
  • 7,968
  • 4
  • 32
  • 36
  • What edge cases do you mean? Please refer to my solution here: http://stackoverflow.com/a/12900504/1249581. It works fine in all cases and much faster than any regex one. – VisioN Oct 06 '13 at 08:17
  • I've already listed the edge cases. And your solution does NOT handle them properly. Like I've already written, try "/dir.with.dot/file". Your code returns "dot/file" which is ridiculously wrong. – mrbrdo Oct 13 '13 at 15:41
  • 1
    No one requested to parse the path. The question was about extracting extensions from filenames. – VisioN Oct 13 '13 at 15:59
  • 3
    Like I already told you, that was never explicitly said, and a solution which handles paths is obviously much more useful. The answer to a question on SO is supposed to be useful to other people besides the person who asked the question. I really don't think a solution that handles a superset of inputs should be downvoted. – mrbrdo Oct 18 '13 at 15:32
  • 3
    The downvote was for using global variable with `.exec()`. Your code will be better as `(filename.match(/[^\\/]\.([^\\/.]+)$/) || [null]).pop()`. – VisioN Oct 18 '13 at 16:15
7

// 获取文件后缀名
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"));
山茶树和葡萄树
  • 2,050
  • 1
  • 18
  • 18
7

There's also a simple approach using ES6 destructuring:

const path = 'hello.world.txt'
const [extension, ...nameParts] = path.split('.').reverse();
console.log('extension:', extension);
Mateja Petrovic
  • 3,799
  • 4
  • 25
  • 40
6

i just wanted to share this.

fileName.slice(fileName.lastIndexOf('.'))

although this has a downfall that files with no extension will return last string. but if you do so this will fix every thing :

   function getExtention(fileName){
     var i = fileName.lastIndexOf('.');
     if(i === -1 ) return false;
     return fileName.slice(i)
   }
Hussein Nazzal
  • 2,557
  • 18
  • 35
  • As far as I remember `slice` method refers to arrays rather than to strings. For strings `substr` or `substring` will work. – VisioN Oct 06 '13 at 08:20
  • @VisioN but i guess you should know that there is `String.prototype.slice` and also a `Array.prototype.slice` so it kinda both work ways kinda of method – Hussein Nazzal Oct 06 '13 at 12:35
6

"one-liner" to get filename and extension using reduce and 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});

with better indentation :

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"
// }
boehm_s
  • 5,254
  • 4
  • 30
  • 44
5
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;
}

//usage

extension('file.jpeg')

always returns the extension lower cas so you can check it on field change works for:

file.JpEg

file (no extension)

file. (noextension)

Jim Blackler
  • 22,946
  • 12
  • 85
  • 101
5

This simple solution

function extension(filename) {
  var r = /.+\.(.+)$/.exec(filename);
  return r ? r[1] : null;
}

Tests

/* 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;
}
Vitim.us
  • 20,746
  • 15
  • 92
  • 109
5

I'm sure someone can, and will, minify and/or optimize my code in the future. But, as of right now, I am 200% confident that my code works in every unique situation (e.g. with just the file name only, with relative, root-relative, and absolute URL's, with fragment # tags, with query ? strings, and whatever else you may decide to throw at it), flawlessly, and with pin-point precision.

For proof, visit: https://projects.jamesandersonjr.com/web/js_projects/get_file_extension_test.php

Here's the JSFiddle: https://jsfiddle.net/JamesAndersonJr/ffcdd5z3/

Not to be overconfident, or blowing my own trumpet, but I haven't seen any block of code for this task (finding the 'correct' file extension, amidst a battery of different function input arguments) that works as well as this does.

Note: By design, if a file extension doesn't exist for the given input string, it simply returns a blank string "", not an error, nor an error message.

It takes two arguments:

  • String: fileNameOrURL (self-explanatory)

  • Boolean: showUnixDotFiles (Whether or Not to show files that begin with a dot ".")

Note (2): If you like my code, be sure to add it to your js library's, and/or repo's, because I worked hard on perfecting it, and it would be a shame to go to waste. So, without further ado, here it is:

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;
    };

Enjoy! You're Quite Welcome!:

Community
  • 1
  • 1
James Anderson Jr.
  • 760
  • 1
  • 8
  • 26
4

If you are looking for a specific extension and know its length, you can use substr:

var file1 = "50.xsl";

if (file1.substr(-4) == '.xsl') {
  // do something
}

JavaScript reference: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/substr

Krisztián Balla
  • 19,223
  • 13
  • 68
  • 84
  • 1
    Beauty comes with simplicity. This is the smartest, more elegant and more efficient answer of all. I always used String.substr(-3) or String.substr(-4) to grab extensions on Windows based systems. Why would someone want to use regular expressions and crazy loops for that. – asiby Sep 14 '14 at 00:07
  • 14
    @asiby This sort of solutions is the main reason for space rockets crashing after launch. – VisioN Jan 12 '15 at 17:44
4

Try this:

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;
}
Darren
  • 68,902
  • 24
  • 138
  • 144
Edward
  • 41
  • 1
3

I just realized that it's not enough to put a comment on p4bl0's answer, though Tom's answer clearly solves the problem:

return filename.replace(/^.*?\.([a-zA-Z0-9]+)$/, "$1");
roenving
  • 2,560
  • 14
  • 14
3

I'm many moons late to the party but for simplicity I use something like this

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>
3

A one line solution that will also account for query params and any characters in url.

string.match(/(.*)\??/i).shift().replace(/\?.*/, '').split('.').pop()

// Example
// some.url.com/with.in/&ot.s/files/file.jpg?spec=1&.ext=jpg
// jpg
Labithiotis
  • 3,519
  • 7
  • 27
  • 47
  • **(1)** If a file has no extension, this will still return the file name. **(2)** If there is a fragment in the URL, but no query (e.g. `page.html#fragment`), this will return the file extension and the fragment. – Jack Jul 10 '16 at 01:03
3
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");
  }
}
Jim Blackler
  • 22,946
  • 12
  • 85
  • 101
3

For most applications, a simple script such as

return /[^.]+$/.exec(filename);

would work just fine (as provided by Tom). However this is not fool proof. It does not work if the following file name is provided:

image.jpg?foo=bar

It may be a bit overkill but I would suggest using a url parser such as this one to avoid failure due to unpredictable filenames.

Using that particular function, you could get the file name like this:

var trueFileName = parse_url('image.jpg?foo=bar').file;

This will output "image.jpg" without the url vars. Then you are free to grab the file extension.

Justin Bull
  • 7,785
  • 6
  • 26
  • 30
2
fetchFileExtention(fileName) {
    return fileName.slice((fileName.lastIndexOf(".") - 1 >>> 0) + 2);
}
GauRang Omar
  • 861
  • 9
  • 20
  • 2
    While this code snippet may solve the question, [including an explanation](http://meta.stackexchange.com/questions/114762/explaining-entirely-code-based-answers) really helps to improve the quality of your post. Remember that you are answering the question for readers in the future, and those people might not know the reasons for your code suggestion. – Brett DeWoody Mar 27 '18 at 08:54
1

Wallacer's answer is nice, but one more checking is needed.

If file has no extension, it will use filename as extension which is not good.

Try this one:

return ( filename.indexOf('.') > 0 ) ? filename.split('.').pop().toLowerCase() : 'undefined';
crab
  • 508
  • 6
  • 6
1

Don't forget that some files can have no extension, so:

var parts = filename.split('.');
return (parts.length > 1) ? parts.pop() : '';
Tamás Pap
  • 17,777
  • 15
  • 70
  • 102
1
return filename.replace(/\.([a-zA-Z0-9]+)$/, "$1");

edit: Strangely (or maybe it's not) the $1 in the second argument of the replace method doesn't seem to work... Sorry.

p4bl0
  • 3,846
  • 1
  • 22
  • 21
  • 1
    It works perfect, but you missed out that you'll have to remove all the other content of the string: return filename.replace(/^.*?\.([a-zA-Z0-9]+)$/, "$1"); – roenving Oct 10 '08 at 14:03
1

In node.js, this can be achieved by the following code:

var file1 ="50.xsl";
var path = require('path');
console.log(path.parse(file1).name);
Jibesh Patra
  • 6,094
  • 1
  • 14
  • 14
1
var file = "hello.txt";
var ext = (function(file, lio) { 
  return lio === -1 ? undefined : file.substring(lio+1); 
})(file, file.lastIndexOf("."));

// hello.txt -> txt
// hello.dolly.txt -> txt
// hello -> undefined
// .hello -> hello
NSD
  • 428
  • 4
  • 4
1

I know this is an old question, but I wrote this function with tests for extracting file extension, and her available with NPM, Yarn, Bit.
Maybe it will help someone.
https://bit.dev/joshk/jotils/get-file-extension

function getFileExtension(path: string): string {
    var regexp = /\.([0-9a-z]+)(?:[\?#]|$)/i
    var extension = path.match(regexp)
    return extension && extension[1]
}

You can see the tests I wrote here.

Josh
  • 670
  • 7
  • 14
1

Simple way to get filename even multiple dot in name

var filename = "my.filehere.txt";

file_name =  filename.replace('.'+filename.split('.').pop(),'');

console.log("Filename =>"+file_name);

OutPut : my.filehere

extension = filename.split('.').pop();
console.log("Extension =>"+extension);

OutPut : txt

Try this is one line code

manoj patel
  • 1,150
  • 12
  • 10
  • And what about `my.backup.name.tar.gz`, let's just that's the file user uploaded. We cannot tell user to not use dot in their file name – Kasir Barati May 26 '23 at 20:08
0
var filetypeArray = (file.type).split("/");
var filetype = filetypeArray[1];

This is a better approach imo.

Chathuranga
  • 1,008
  • 1
  • 15
  • 26
0

I prefer to use lodash for most things so here's a solution:

function getExtensionFromFilename(filename) {
    let extension = '';
    if (filename > '') {
        let parts = _.split(filename, '.');
        if (parts.length >= 2) {
        extension = _.last(parts);
    }
    return extension;
}
omarjebari
  • 4,861
  • 3
  • 34
  • 32