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.