JavaScript正则表达式匹配/提取文件扩展名

49
以下正则表达式:
var patt1=/[0-9a-z]+$/i;

从字符串中提取文件扩展名,例如

filename-jpg
filename#gif
filename.png

如何修改这个正则表达式,以便仅在字符串真正是一个只有一个点作为分隔符的文件名时返回扩展名?(显然,filename#gif不是一个常规的文件名)
更新:根据tvanofsson的评论,我想澄清一下,当JS函数接收到字符串时,该字符串将已经包含没有空格、没有点和其他特殊字符的文件名(实际上它将被处理为一个“slug”)。问题不在于解析文件名,而是在于错误地解析“slug”——当给定“filename-jpg”时,该函数返回了“jpg”的扩展名,而实际上应该返回null或空字符串,并且需要纠正这种行为。

4
正则表达式是否需要确定文件名是否是合法的?什么定义了合法的文件名?什么定义了合法的文件名扩展名?例如,foo bar.zi_ 是合法文件名吗?foo.bar.zi_ 呢? - tvanfosson
典型的操作系统文件名...在我们的系统中不可能出现您带有空格的示例,@stema提供的答案似乎可以处理双扩展名,所以对我来说已经足够好了。 - mare
2
这两个例子都是Unix和Windows下合法的文件名。你的问题如果能详细说明你认为什么样的文件名是合法的,将会使得答案更有意义,尤其是对于未来可能想解决相同或类似问题的读者。 - tvanfosson
6个回答

97
只需在正则表达式中添加一个 .
var patt1=/\.[0-9a-z]+$/i;

由于点号是正则表达式中的特殊字符,因此您需要使用转义字符 \.来匹配它。

现在,您的模式将匹配以点号结尾并且后面至少有一个来自[0-9a-z]集合中的字符的任何字符串。

示例:

[
  "foobar.a",
  "foobar.txt",
  "foobar.foobar1234"
].forEach( t => 
  console.log(
    t.match(/\.[0-9a-z]+$/i)[0]
  ) 
)


如果你想限制扩展名的字符数量,那么你需要替换 +
var patt1=/\.[0-9a-z]{1,5}$/i;

允许在点号后至少输入1个字符,最多输入5个字符。


如果我不需要匹配中的点,只需要扩展名怎么办? - user2727195
1
@user2727195 如果没有点,则无法匹配扩展名。如果您的意思是......如何仅使用结果文本,那么可以使用substring,如下所示:(("file.ext").match(patt1) ||'').substring(1); - Armstrongest
1
同样适用于.tar.gz扩展名的失败。 - Ravi Theja
上面的注释中的代码对我不起作用。如果你只想要扩展名而不是点,可以这样做... const ext = ("file.ext".match(/\.[0-9a-z]{1,5}$/i) || [""])[0].substring(1) - chichilatte
在糟糕的情况下,这个解决方案将导致 NULL。 - STEEL

51

尝试

var patt1 = /\.([0-9a-z]+)(?:[\?#]|$)/i;

这个正则表达式适用于从URL中提取文件扩展名,即使是具有?foo=1查询字符串和#hash结束的URL也可以。

它还会将扩展名作为$1提供给你。

var m1 = ("filename-jpg").match(patt1);
alert(m1);  // null

var m2 = ("filename#gif").match(patt1);
alert(m2);  // null

var m3 = ("filename.png").match(patt1);
alert(m3);  // [".png", "png"]

var m4 = ("filename.txt?foo=1").match(patt1);
alert(m4);  // [".txt?", "txt"]

var m5 = ("filename.html#hash").match(patt1);
alert(m5);  // [".html#", "html"]

P.S. +1 给 @stema,他在回答中给出了非常好的建议,涉及到一些正则表达式语法基础知识。


17

示例列表:

var fileExtensionPattern = /\.([0-9a-z]+)(?=[?#])|(\.)(?:[\w]+)$/gmi
//regex flags -- Global, Multiline, Insensitive

var ma1 = 'css/global.css?v=1.2'.match(fileExtensionPattern)[0];
console.log(ma1);
// returns .css

var ma2 = 'index.html?a=param'.match(fileExtensionPattern)[0];
console.log(ma2);
// returns .html

var ma3 = 'default.aspx?'.match(fileExtensionPattern)[0];
console.log(ma3);
// returns .aspx

var ma4 = 'pages.jsp#firstTab'.match(fileExtensionPattern)[0];
console.log(ma4);
// returns .jsp

var ma5 = 'jquery.min.js'.match(fileExtensionPattern)[0];
console.log(ma5);
// returns .js

var ma6 = 'file.123'.match(fileExtensionPattern)[0];
console.log(ma6);
// returns .123

测试页面


7

简介:

let ext = (filename.match(/\.([^.]*?)(?=\?|#|$)/) || [])[1] 

上述解决方案包含链接。它获取最后一个点和第一个"?"或"#"字符或字符串结尾之间的所有内容。要忽略"?"和"#"字符,请使用/\.([^.]*)$/。要仅忽略"#",请使用/\.([^.]*?)(?=\?|$)/。示例:

function getExtension(filename) {
  return (filename.match(/\.([^.]*?)(?=\?|#|$)/) || [])[1];
}


// TEST
[
  "abcd.Ef1",
  "abcd.efg",
  "abcd.efg?aaa&a?a=b#cb",
  "abcd.efg#aaa__aa?bb",
  "abcd",
  "abcdefg?aaa&aa=bb",
  "abcdefg#aaa__bb",
].forEach(t=> console.log(`${t.padEnd(21,' ')} -> ${getExtension(t)}`))


3

我在O'Reilly正则表达式手册(第8章,第24节)上找到了这个解决方案。它不区分大小写,并适用于.NET、Java、JavaScript、PCRE、Perl、Python和Ruby。

\.[^.\\/:*?"<>|\r\n]+$

一个文件扩展名必须以点号开始。因此,在正则表达式的开头添加‹.›以匹配字面上的点号。
例如,Version 2.0.txt 这样的文件名可能包含多个点号。最后一个点号是将扩展名与文件名分隔开的点号。扩展名本身不应包含任何点号。我们在字符类中放置一个点号来指定这一点。点号只是字符类中的一个字面字符,因此我们不需要转义它。正则表达式末尾的 ‹$› 锚定符确保我们匹配 .txt 而不是 .0。
如果字符串以反斜杠结尾,或者以不包含任何点号的文件名结尾,则正则表达式将完全不匹配。当它匹配时,它将匹配扩展名,包括分隔扩展名的点号和...

0

我建议使用这个函数,因为它避免了返回null

const getExtension = (filename?: string): string | undefined => {
  if (!filename) return undefined
  const match = /\.([^.]+)$/.exec(filename)
  return match ? match[1] : undefined
}

这个函数接受一个可选的文件名参数,该参数可以是未定义的。如果文件名未定义,则函数返回未定义。否则,函数使用正则表达式从文件名中提取文件扩展名。如果正则表达式匹配成功,则函数返回提取的文件扩展名;否则,它返回未定义。

const getExtension = (filename) => {
  if (!filename) return undefined
  const match = /\.([^.]+)$/.exec(filename)
  return match ? match[1] : undefined
}

[
  "a.abc.x.ico",
  "foobar.a",
  "foobar.txt",
  "foobar.foobar1234",
  "undegined",
  undefined, null
].forEach(t =>
  console.log(
    getExtension(t)
  )
)


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