如何检查字符串是否是有效的 Figma link?

How to check if string is a valid Figma link?

我正在使用 Figma API 在 NodeJS 上构建一个应用程序,我需要检查用户传递的字符串是否是有效的 Figma link。我目前正在使用这个简单的正则表达式来检查字符串:

/^https\:\/\/www.figma.com\/.*/i

但是,它匹配 figma.com 中的所有 link,甚至是主页,而不仅仅是文件和原型的 link。这是一个 Figma link 应该匹配的例子:

https://www.figma.com/file/OoYmkiTlusAzIjYwAgSbv8wy/Test-File?node-id=0%3A1

如果这是原型 link,则匹配也应该是肯定的,路径中使用 proto 而不是 file

此外,由于我使用的是 Figma API,因此同时提取 URL 的必要部分(例如文件 ID 和节点 ID)会很有用。

TL;DR

✅ 使用此表达式捕获四个最重要的组(类型、文件 ID、文件名和 URL 属性)并从那里开始工作。

/^(?:https:\/\/)?(?:www\.)?figma\.com\/(file|proto)\/([0-9a-zA-Z]{22,128})(?:\/?([^\?]+)?(.*))?$/

来自文档

这是 Figma 在其 developer documentation page about embeds 上提供的正则表达式代码:

/https://([w.-]+.)?figma.com/(file|proto)/([0-9a-zA-Z]{22,128})(?:/.*)?$/

然而,它在 JS 中不起作用,因为 文档目前是错误的并且这个表达式有多个问题:

  • 斜杠和点不使用反斜杠转义。

  • 从字符串开头不匹配。在 VLAZ 在评论中指出后,我添加了 start of string anchor ^。这样我们将避免匹配不以 https 开头的字符串,例如 malicious.site/?link=https://figma.com/...

  • 它不仅会匹配 www. 子域,还会匹配任何其他数量不大的 W(例如 wwwww.)——可以通过将字母匹配替换为更简单的表达。另外这是一个无用的捕获组,我将其设为非捕获。

  • 如果 link 匹配,即使它不以 https:// 开头也很好,因为某些引擎(例如 Twitter)为了简洁而删除了这部分,如果有人正在从那里复制一个 link,它应该仍然有效。

应用所有改进后,我们得到以下表达式:

/^(?:https:\/\/)?(?:www\.)?figma\.com\/(file|proto)\/([0-9a-zA-Z]{22,128})(?:\/.*)?$/

还有一个专门的 NPM package 可以根据类似模式简单地检查 URL。但是,它包含上面列出的一些缺陷,所以我不建议使用它,尤其是对于只有一行代码的情况。


正在提取 URL

的部分内容

这个表达式与 Figma API 一起使用非常有用,因为它甚至可以从 URL 中提取必要的部分,例如 link (proto/file) 的类型和file key。您可以通过索引访问它们。

您还可以添加一个 piece of regex 来匹配查询中的特定键,例如 node-id:

/^(?:https:\/\/)?(?:www\.)?figma\.com\/(file|proto)\/([0-9a-zA-Z]{22,128})(?:\/.*)?node-id=([^&]*)$/

现在您可以在代码中使用它并分别获取 URL 的所有部分:

var pattern = /^(?:https:\/\/)?(?:www\.)?figma\.com\/(file|proto)\/([0-9a-zA-Z]{22,128})(?:\/.*)?node-id=([^&]*)$/

var matched = 'https://www.figma.com/file/OoYmkiTlusAzIjYwAgSbv8wy/Test-File?node-id=0%3A1'.match(pattern)

console.log('url:', matched[0]) // whole matched string
console.log('type:', matched[1]) // group 1
console.log('file key:', matched[2]) // group 2
console.log('node id:', matched[3]) // group 3


深入挖掘

我花了一些时间几乎从头开始重新创建这个表达式,所以它可以匹配尽可能多的 Figma file/prototype URLs 而不会破坏任何东西。这是适用于不同情况的三个相似版本。

✅ 此版本将 URL 参数和文件名分开捕获,以便于处理。你可以check it here。我把它添加在答案的开头,因为我认为它是最干净和最有用的解决方案。

/^(?:https:\/\/)?(?:www\.)?figma\.com\/(file|proto)\/([0-9a-zA-Z]{22,128})(?:\/?([^\?]+)?(.*))?$/

其中的分组如下:

  • 第 1 组:file/proto
  • 第 2 组:文件 key/id
  • 第 3 组:文件名(可选)
  • 第 4 组:url 参数(可选)

✅ 接下来,我想做同样的事情,但将可以添加到任何 Figma URL 末尾的 /duplicate 部分分开,以便在打开时创建文件的副本。

/^(?:https:\/\/)?(?:www\.)?figma\.com\/(file|proto)\/([0-9a-zA-Z]{22,128})(?:\/?([^\?]+)?([^\/]*)(\/duplicate)?)?$/

✅ 回到 node-id 参数。以下正则表达式成功地在 多行字符串 中查找并捕获多个 URL。我最后发现的唯一缺点是它(以及之前的所有缺点)不检查此 URL 是否包含未编码的 special characters meaning that it can potentially break things, but it can be avoided by manually encoding all parameters using encodeURI() function.

/^(?:https:\/\/)?(?:www\.)?figma\.com\/(file|proto)\/([0-9a-zA-Z]{22,128})(?:\/([^\?\n\r\/]+)?((?:\?[^\/]*?node-id=([^&\n\r\/]+))?[^\/]*?)(\/duplicate)?)?$/gm

这个表达式可以捕获六个组:

  • 第 1 组:file/proto
  • 第 2 组:文件 key/id
  • 第 3 组:文件名(可选)
  • 第 4 组:url 参数(可选)
    • 第 5 组:节点 ID(可选;仅当存在第 4 组时出现)
  • 第 6 组:/重复

最后,这里是匹配及其组(或 try it yourself)的示例: