Reputation: 266920
I have a url like http://www.example.com/blah/th.html
I need a javascript function to give me the 'th' value from that.
All my urls have the same format (2 letter filenames, with .html extension).
I want it to be a safe function, so if someone passes in an empty url it doesn't break.
I know how to check for length, but I should be checking for null to right?
Upvotes: 100
Views: 121538
Reputation: 6394
Other way to convert to URL first:
function getFilenameFromUrl(url: string): string | null {
try {
const parsedUrl = new URL(url);
const pathname = parsedUrl.pathname;
const pathComponents = pathname.split('/');
const filename = pathComponents[pathComponents.length - 1]; // Get the last component (filename)
return filename;
} catch (error) {
console.error('Error parsing URL:', error);
return null;
}
}
// Example usage:
const url = "https://example.com/api/alerting/image/f1635b2b-7946-422a-85c1-aaf52f0e944a/1f5f648d-cc0d-4c95-b06f-eb28b770156d8436546758293928039.zip";
const filename = getFilenameFromUrl(url);
if (filename) {
console.log('Filename extracted:', filename);
} else {
console.log('Failed to extract filename from URL');
}
Upvotes: 0
Reputation: 500
if any lazy person just wants the file name without extension,here it is
const url='https://test.s3.us-west-2.amazonaws.com/d.pdf';
const filename = url.split('/').pop().split('.')[0] //187392504
Upvotes: 0
Reputation: 1232
Why so difficult?
= url.split('#')[0].split('?')[0].split('/').pop();
RegEx below would result same as the above's normally, but will return empty string if the URL was significantly malformed.
= (url.match(/^\w+:(\/+([^\/#?\s]+)){2,}(#|\?|$)/)||[])[2]||'';
// Returns empty string for relative URLs unlike the original approach
= (url.match(/^\w+:(\/+([^\/#?\s]+)){2,}/)||[])[2]||'';
// Ignores trailing slash (e.g., ".../posts/?a#b" results "posts")
All three of them would return file😃.name
from:
my://host/path=&%dir///file😃.name?q=1/2&3=&#a/?b//?
The third one would also return dir.name
from:
my://host/path=&%dir///dir.name/?not/these/#/ones//?
First Edit (Sep 2023) :
Try to test your URL by enter below. The third one would ignores trailing slash as described the above code. Please comment if the RegEx ones wouldn't properly handle any valid URL
<style>*{margin:0;padding:0;box-sizing:border-box;border:none;}label{font-size:90%}input{display:block;margin:.2em auto 0;padding:.8em 1.2em;width:calc(100% - 5px);background:#f8f8f8;border-radius:1em;}p{margin-top:1.4em;padding-left:.5em;font-size:95%;color:#0008}p::after{content:attr(title);margin-left:.5em;padding:.4em .2em;background:#fe8;border-radius:.5em;font-weight:800;color:#000;}</style>
<label for="input">Enter your URL here:</label>
<input value="my://host/path=&%dir///file😃.name?q=1/2&3=&#a/?b//?" id="input">
<p>A</p>
<p>B</p>
<p>C</p>
<script>
((input = document.querySelector('input'), output = document.querySelectorAll('p')) => {
const getFilename = _=> {
output[0].title = input.value.split('#')[0].split('?')[0].split('/').pop();
output[1].title = (input.value.match(/^\w+:(\/+([^\/#?\s]+)){2,}(#|\?|$)/)||[])[2]||'';
output[2].title = (input.value.match(/^\w+:(\/+([^\/#?\s]+)){2,}/)||[])[2]||'';
};
getFilename();
input.addEventListener('input', getFilename);
input.select();
})();
</script>
Upvotes: 109
Reputation: 846
function getFilenameFromUrlString(url) {
const response = {
data: {
filename: ""
},
error: ""
};
try {
response.data.filename = new URL(url).pathname.split("/").pop();
} catch (e) {
response.error = e.toString();
}
return response;
}
For tests check this: https://codesandbox.io/s/get-filename-from-url-string-wqthx1
Upvotes: 0
Reputation: 2382
Let´s say you have this url:
http://127.0.0.1:3000/pages/blog/posts/1660345251.html
Using the following line of code:
var filename = location.pathname.replace(/[\D]/g, "");
Will return:
1660345251
.replace(/[\D]/g, "")
, replaces any non-digit character with an empty string. /[\D]/g
says non-digit, and ""
says empty string. More about it: here for numbers and here for letters.filename
.var humanDate = new Date(0);
var timestamp = entries[index].timestamp;
humanDate.setUTCSeconds(timestamp);
humanDate
is for my local time:
Fri Aug 12 2022 20:00:51 GMT-0300 (Argentina Standard Time)
Credits for this code, here.
Upvotes: 0
Reputation: 3978
This should work for all cases
function getFilenameFromUrl(url) {
const pathname = new URL(url).pathname;
const index = pathname.lastIndexOf('/');
return pathname.substring(index + 1) // if index === -1 then index+1 will be 0
}
Upvotes: 12
Reputation: 1101
function pathInfo(s) {
s=s.match(/(.*?\/)?(([^/]*?)(\.[^/.]+?)?)(?:[?#].*)?$/);
return {path:s[1],file:s[2],name:s[3],ext:s[4]};
}
var sample='/folder/another/file.min.js?query=1';
var result=pathInfo(sample);
console.log(result);
/*
{
"path": "/folder/another/",
"file": "file.min.js",
"name": "file.min",
"ext": ".js"
}
*/
console.log(result.name);
Upvotes: 0
Reputation: 9163
This should handle anything you throw at it (absolute URLs, relative URLs, complex AWS URLs, etc). It includes an optional default or uses a psuedorandom string if neither a filename nor a default were present.
function parseUrlFilename(url, defaultFilename = null) {
let filename = new URL(url, "https://example.com").href.split("#").shift().split("?").shift().split("/").pop(); //No need to change "https://example.com"; it's only present to allow for processing relative URLs.
if(!filename) {
if(defaultFilename) {
filename = defaultFilename;
//No default filename provided; use a pseudorandom string.
} else {
filename = Math.random().toString(36).substr(2, 10);
}
}
return filename;
}
Props to @hayatbiralem for nailing the order of the split()
s.
Upvotes: 2
Reputation: 8572
In addition to the existing answers, I would recommend using URL() constructor
(works both in browsers and Node.js) because you can be sure your URL is valid:
const url = 'https://test.com/path/photo123.png?param1=1¶m2=2#hash';
let filename = '';
try {
filename = new URL(url).pathname.split('/').pop();
} catch (e) {
console.error(e);
}
console.log(`filename: ${filename}`);
Upvotes: 18
Reputation: 32482
Actually, the marked answer is true but if the second if
doesn't satisfy the function returns undefined
, I prefer to write it like below:
const getFileNameFromUrl = (url: string): string => {
if (url) {
const tmp = url.split('/');
const tmpLength = tmp.length;
return tmpLength ? tmp[tmpLength - 1] : '';
}
return '';
};
For my problem, I need to have the file extension.
Upvotes: 0
Reputation: 1291
Because cases tend to fail with custom code, I looked up to the JavaScript URL
class. Alas, it chokes on relative URLs! Also, it doesn't have a property to get the file name. Not epic.
There has to be a good library out there which solves this common problem. Behold URI.js. All you need is a simple statement like the following:
let file = new URI(url).filename()
Then we can create a simple function that does null checks and removes the file extension:
function fileName(url) {
if (url === null || typeof url === 'undefined')
return ''
let file = new URI(url).filename() // File name with file extension
return file.substring(0, file.lastIndexOf('.')) // Remove the extension
}
Here's a snippet with test cases to play around with. All cases pass except drive paths.
test('Dots in file name without URL', 'dotted.file.name.png', 'dotted.file.name')
test('Dots in file name with URL', 'http://example.com/file.name.txt', 'file.name')
test('Lengthy URL with parameters', '/my/folder/filename.html#dssddsdsd?toto=33&dududu=podpodpo', 'filename')
test('URL with hash', '/my/folder/filename.html#dssddsdsd', 'filename')
test('URL with query strings', '/my/folder/filename.html?toto=33&dududu=podpodp', 'filename')
test('Hash after query string', 'http://www.myblog.com/filename.php?year=2019#06', 'filename')
test('Query parameter with file path character', 'http://www.example.com/filename.zip?passkey=1/2', 'filename')
test('Query parameter with file path character and hash', 'http://www.example.com/filename.html?lang=en&user=Aan9u/o8ai#top', 'filename')
test('Asian characters', 'http://example.com/文件名.html', '文件名')
test('URL without file name', 'http://www.example.com', '')
test('Null', null, '')
test('Undefined', undefined, '')
test('Empty string', '', '')
test('Drive path name', 'C:/fakepath/filename.csv', 'filename')
function fileName(url) {
if (url === null || typeof url === 'undefined')
return ''
let file = new URI(url).filename() // File name with file extension
return file.substring(0, file.lastIndexOf('.')) // Remove the extension
}
function test(description, input, expected) {
let result = fileName(input)
let pass = 'FAIL'
if (result === expected)
pass = 'PASS'
console.log(pass + ': ' + description + ': ' + input)
console.log(' => "' + fileName(input) + '"')
}
<script src="https://cdn.jsdelivr.net/gh/medialize/URI.js@master/src/URI.js"></script>
Results
PASS: Dots in file name without URL: dotted.file.name.png
=> "dotted.file.name"
PASS: Dots in file name with URL: http://example.com/file.name.txt
=> "file.name"
PASS: Lengthy URL with parameters: /my/folder/filename.html#dssddsdsd?toto=33&dududu=podpodpo
=> "filename"
PASS: URL with hash: /my/folder/filename.html#dssddsdsd
=> "filename"
PASS: URL with query strings: /my/folder/filename.html?toto=33&dududu=podpodp
=> "filename"
PASS: Hash after query string: http://www.myblog.com/filename.php?year=2019#06
=> "filename"
PASS: Query parameter with file path character: http://www.example.com/filename.zip?passkey=1/2
=> "filename"
PASS: Query parameter with file path character and hash: http://www.example.com/filename.html?lang=en&user=Aan9u/o8ai#top
=> "filename"
PASS: Asian characters: http://example.com/文件名.html
=> "文件名"
PASS: URL without file name: http://www.example.com
=> ""
PASS: Null: null
=> ""
PASS: Undefined: undefined
=> ""
PASS: Empty string:
=> ""
FAIL: Drive path name: C:/fakepath/filename.csv
=> ""
This solution is for you if you're too lazy to write custom code and don't mind using a library to do work for you. It isn't for you if you want to code golf the solution.
Upvotes: 6
Reputation: 4738
This answer only works in browser environment. Not suitable for node.
function getFilename(url) {
const filename = decodeURIComponent(new URL(url).pathname.split('/').pop());
if (!filename) return 'index.html'; // some default filename
return filename;
}
function filenameWithoutExtension(filename) {
return filename.replace(/^(.+?)(?:\.[^.]*)?$/, '$1');
}
Here are two functions:
For parsing URL, new an URL
object should be the best choice. Also notice that URL do not always contain a filename.
Notice: This function try to resolve filename from an URL. But it do NOT guarantee that the filename is valid and suitable for use:
:
in windows, \0
in most OS, ...);CON
in windows);Test it out:
function getFilename(url) {
const filename = decodeURIComponent(new URL(url).pathname.split('/').pop());
if (!filename) return 'index.html'; // some default filename
return filename;
}
function test(url) {
console.log('Filename: %o\nUrl: %o', getFilename(url), url);
}
test('http://www.example.com');
test('http://www.example.com/');
test('http://www.example.com/name.txt');
test('http://www.example.com/path/name.txt');
test('http://www.example.com/path/name.txt/realname.txt');
test('http://www.example.com/page.html#!/home');
test('http://www.example.com/page.html?lang=en&user=Aan9u/o8ai#top');
test('http://www.example.com/%E6%96%87%E4%BB%B6%E5%90%8D.txt')
Upvotes: 5
Reputation: 7037
For node and browsers, based on @pauls answer but solving issues with hash and more defensive:
export function getFileNameFromUrl(url) {
const hashIndex = url.indexOf('#')
url = hashIndex !== -1 ? url.substring(0, hashIndex) : url
return (url.split('/').pop() || '').replace(/[\?].*$/g, '')
}
Few cases:
describe('getFileNameFromUrl', () => {
it('absolute, hash and no extension', () => {
expect(getFileNameFromUrl(
'https://foo.bar/qs/bar/js-function-to-get-filename-from-url#comment95124061_53560218'))
.toBe('js-function-to-get-filename-from-url')
})
it('relative, extension and parameters', () => {
expect(getFileNameFromUrl('../foo.png?ar=8')).toBe('foo.png')
})
it('file name with multiple dots, hash with slash', () => {
expect(getFileNameFromUrl('questions/511761/js-function.min.js?bar=9.9&y=1#/src/jjj?=9.9')).toBe('js-function.min.js')
})
})
Upvotes: 1
Reputation: 2402
function getFileNameWithoutExtension(url) {
if (typeof url !== 'string') throw new Error('url must be a string');
// Remove the QueryString
return url.replace(/\?.*$/, '')
// Extract the filename
.split('/').pop()
// Remove the extension
.replace(/\.[^.]+$/, '');
}
This will return news
from this URL http://www.myblog.com/news.php?year=2019#06.
Upvotes: 0
Reputation:
url? url.substring(url.lastIndexOf('/')+1, url.lastIndexOf('.')):''
null
or undefined
the result is ''
.It allows filename to have several periods!
Not asked, but you can also have a query string without '/' and '.'
It is a corrected answer from Abhishek Sharma so I gave him an upvote. So genious and minimal one-liner - I saw it there :)
Upvotes: 0
Reputation: 750
from How to get the file name from a full path using JavaScript?
var filename = fullPath.replace(/^.*[\\\/]/, '')
Upvotes: -1
Reputation: 1680
A regex solution which accounts for URL query and hash identifier:
function fileNameFromUrl(url) {
var matches = url.match(/\/([^\/?#]+)[^\/]*$/);
if (matches.length > 1) {
return matches[1];
}
return null;
}
JSFiddle here.
Upvotes: 9
Reputation: 7683
my 2 cents
the LastIndexOf("/") method in itself falls down if the querystrings contain "/"
We all know they "should" be encoded as %2F
but it would only take one un-escaped value to cause problems.
This version correctly handles /'s in the querystrings and has no reliance on .'s in the url
function getPageName() {
//#### Grab the url
var FullUrl = window.location.href;
//#### Remove QueryStrings
var UrlSegments = FullUrl.split("?")
FullUrl = UrlSegments[0];
//#### Extract the filename
return FullUrl.substr(FullUrl.lastIndexOf("/") + 1);
}
Upvotes: 0
Reputation: 715
those will not work for lenghty url like
"/my/folder/questions.html#dssddsdsd?toto=33&dududu=podpodpo"
here I expect to get "questions.html". So a possible (slow) solution is as below
fname=function(url)
{ return url?url.split('/').pop().split('#').shift().split('?').shift():null }
then you can test that in any case you get only the filename.
fname("/my/folder/questions.html#dssddsdsd?toto=33&dududu=podpodpo")
-->"questions.html"
fname("/my/folder/questions.html#dssddsdsd")
-->"questions.html"
fname("/my/folder/questions.html?toto=33&dududu=podpodpo")
"-->questions.html"
(and it works for null)
(I would love to see a faster or smarter solution)
Upvotes: 5
Reputation: 3068
Similar to the others, but...I've used Tom's simple script - a single line,
then you can use the filename var anywhere:
http://www.tomhoppe.com/index.php/2008/02/grab-filename-from-window-location/
var filename = location.pathname.substr(location.pathname.lastIndexOf("/")+1);
Upvotes: 16
Reputation: 366
Similarly to what @user2492653 suggested, if all you want is the name of the file like Firefox gives you, then you the split() method, which breaks the string into an array of components, then all you need to do it grab the last index.
var temp = url.split("//");
if(temp.length > 1)
return temp[temp.length-1] //length-1 since array indexes start at 0
This would basically break C:/fakepath/test.csv into {"C:", "fakepath", "test.csv"}
Upvotes: 0
Reputation: 31738
I'd use the substring
function combined with lastIndexOf
. This will allow for filenames with periods in them e.g. given http://example.com/file.name.txt
this gives file.name
unlike the accepted answer that would give file
.
function GetFilename(url)
{
if (url)
{
return url.substring(url.lastIndexOf("/") + 1, url.lastIndexOf("."));
}
return "";
}
Upvotes: 3
Reputation: 15841
Using jQuery with the URL plugin:
var file = jQuery.url.attr("file");
var fileNoExt = file.replace(/\.(html|htm)$/, "");
// file == "th.html", fileNoExt = "th"
Upvotes: 1
Reputation: 16505
Use the match function.
function GetFilename(url)
{
if (url)
{
var m = url.toString().match(/.*\/(.+?)\./);
if (m && m.length > 1)
{
return m[1];
}
}
return "";
}
Upvotes: 31