You can use the following regex pattern to separate the filename from the extension, handling cases where there might not be an extension:
^(.*?)(?:\.([^\.]+))?$
Here's how the regex works:
^(.*?)
: This captures the filename. The ^
asserts the start of a string, and (.+?)
captures zero or more of any characters, non-greedy (as little as possible).(?:\.([^\.]+))?
: This is a non-capturing group for the extension section:\.
: Matches the literal dot.([^\.]+)
: Captures one or more characters that are not a dot. This is our file extension.?
: Makes the entire non-capturing group optional, accounting for filenames without an extension.$
: Asserts the end of the line or string.const regex = /^(.*?)(?:\.([^.]+))?$/
console.log (regex.exec('filename.txt')) // ["filename.txt", "filename", "txt"]
console.log (regex.exec('file.name.txt')) // ["file.name.txt", "file.name", "txt"]
console.log (regex.exec('file.name.with.several.dots.txt')) // ["file.name.txt", "file.name", "txt"]
console.log (regex.exec('filename')) // ["filename", "filename", undefined]
console.log (regex.exec('file.name')) // ["file.name", "file", "name"]
console.log (regex.exec('.htaccess')) // [".htaccess", "", "htaccess"]
console.log (regex.exec('')) // ["", "", undefined]
Check the above example online on JSFiddle
This regex is designed to work well in most environments, including Python, JavaScript, and PCRE (Perl Compatible Regular Expressions).