正则表达式:捕获文件名(不包括 URL 路径和扩展名)

7
在JavaScript中,我可以使用这个正则表达式([^\/]+)(\.[^\.\/]+)$来仅捕获URL中的文件名。它适用于以下情况:
http://a.com/b/file.name.ext
http://a.com/b/file.name.ext#hash
http://a.com/b/file.name.ext?query

然而,如果没有文件扩展名,它将无法匹配:
无匹配
http://a.com/b/filename
http://a.com/b/filename#hash
http://a.com/b/filename?query

这很正常。第二个捕获组期望在结尾处有一个.ext块。
如果我将第二个捕获组设置为可选...
`([^\/]+)(\.[^\.\/]+)?$`

如果第一个捕获组变得贪婪,那么它会包含.ext结尾,而我不希望出现这种情况。正则表达式引擎如何考虑可选的第二个组?如何使扩展名的存在是可选的?


注意:此正则表达式不适用于具有以下结构的URL:

http://a.com/b/filename?query=a.b
http://a.com/b/filename.ext?query=a.b

在我的情况下,URL中不会再出现点。

只需不在第一个贪婪组中匹配点号: ([^\/.]+) - Jo So
@JoSo:文件名中可能会有点。我已经编辑了我的问题以明确这一点。 - James Newton
@JoSo 当然可以!(我试过其他方法,但我没有想到为整个表达式创建替代方案。)([^\/.]+)$|([^\/]+)(\.[^\/.]+)$ 对我有效(在第一个替代方案后加上 $)。如果您愿意将其作为答案给出,我可以为您提供积分。 - James Newton
2
http://a.com/b/filen.ame 中,无法判断 ame 是名称的一部分还是扩展名!!(除非您提供允许的扩展名列表) - Enissay
@Enissay 你说得对。我的假设是,如果文件名中有任何点,则最后一个点是扩展名。但对于其他有类似问题的人来说,情况可能并非如此。 - James Newton
显示剩余2条评论
2个回答

1

如果您想要纯正的正则表达式(即理论计算机科学中漂亮而干净的常规语言表达式,以及捕获组),那么您可以使用备选组来实现:

([^\/.]+)$|([^\/]+)(\.[^\/.]+)$

请识别第一组和第二组。第三组是可选扩展。

另一个可能性:

([^\/.]+)(([^\/]*)(\.[^\/.]+))?$

在这里,您需要使用第4组作为扩展名,并将第1组和第3组连接起来作为文件名。第2组仅用于使3和4的组合可选。

你的第二个命题还可以捕获任何查询或哈希部分,如果没有扩展名。请参见此处:https://regex101.com/r/hB9dK8/1 - James Newton
@JamesNewton 这个页面上的所有正则表达式都捕获了那些内容。但是你可以通过在所有否定组中包含,并且不使用$匹配输入的结尾来避免这种情况。或者更简单的方法是,在匹配之前先删除查询和哈希值。 - Jo So

1

测试环境:

http://a.com/b/file.name.ext
http://a.com/b/filename
http://a.com/b/filename#hash
http://a.com/b/filename?query

var file = "http://a.com/b/filename#hash";
function getFileName(url) {
    var index = url.lastIndexOf("/") + 1;
    var filenameWithExtension = url.substr(index);
    var filename = filenameWithExtension.split(".")[0]; 
    filename = filename.replace(/(#|\?).*?$/, "");
    return filename;                                   
}

alert(getFileName(file));
//filename


参考资料:

lastindexof

split

substr

replace


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接