从 Google Apps 脚本上的 URL 获取文件 ID 的最简单方法

Posted

技术标签:

【中文标题】从 Google Apps 脚本上的 URL 获取文件 ID 的最简单方法【英文标题】:Easiest way to get file ID from URL on Google Apps Script 【发布时间】:2013-05-26 06:10:02 【问题描述】:

这是我想要做的:给定一个 Google 文档 URL,我想获取文档 ID 以在 Google Drive 上创建一个副本。我知道我可以通过一些正则表达式或在 URL 上替换来实现这一点,但是由于有几种不同的形式可以在 URL 中表示同一个文档,所以我想找到一个通用的解决方案。

目前,这是我能想到的最好的:

function getFileIdFromUrl(url) 
  try 
    return getDocIdFromUrl(url);
   catch (e) 
    return getSpreadsheetIdFromUrl(url);
  


function getDocIdFromUrl(url) 
  var doc = null;
  try 
    doc = DocumentApp.openByUrl(url);
   catch (e) 
    doc = DocumentApp.openByUrl(url + "/edit");
  
  return doc.getId();


function getSpreadsheetIdFromUrl(url) 
  var spreadsheet = null;
  try 
    spreadsheet = SpreadsheetApp.openByUrl(url);
   catch (e) 
    spreadsheet = SpreadsheetApp.openByUrl(url + "/edit");
  
  return spreadsheet.getId();


function copy(url)  // may throw an exception if the URL is invalid or private
   var id = getFileIdFromUrl(url);
   var file = DriveApp.getFileById(id);
   file.makeCopy().setSharing(DriveApp.Access.ANYONE_WITH_LINK, DriveApp.Permission.VIEW);

问题是我的解决方案只涵盖文档和电子表格,我想对任何上传的文件做同样的事情,例如:

https://docs.google.com/file/d/0B-FYu_D7D7x4REdtRVEzVH0eU0/edit

简而言之,我想要这样的东西:

DriveApp.getFileByUrl(url).makeCopy();

有人知道这是否可能吗?

任何从文件 URL 中提取文件 ID 的安全解决方案都适合我。

谢谢

【问题讨论】:

【参考方案1】:

DriveApp 确实缺少getFileByUrl(以及与此相关的文件夹)。您可能想在Apps Script issue tracker 上提出增强请求。

但我在我的脚本中所做的(因为这些 openByUrl 函数有些新)是使用正则表达式获取 id。像这样。

function getIdFromUrl(url)  return url.match(/[-\w]25,/); 

此正则表达式适用于我尝试过的任何 google url:文件夹和文件的 Drive url、Fusion Tables、Spreadsheets、Docs、Presentation 等。它只是在字符串中查找“看起来像”Google 密钥的任何内容。也就是说,任何足够大的字符串,其中只有(谷歌键)有效字符。

此外,即使它直接接收 ID 而不是 URL,它也可以工作。当您向用户询问链接时,这很有用,因为有些人可能会直接粘贴 id 而不是 url,但它仍然有效。

--编辑

还有一些其他答案和 cmets 解决了一些我自己从未遇到过但可能会发生的边缘情况,例如尝试在嵌套文件夹 URL 上获取文件夹 ID,或者当您拥有 25 岁以上的 G-Suite 域时长字符。对于这些情况,您可能需要使用更严格的正则表达式。

通过快速浏览下面的建议,我推荐以下/[-\w]25,(?!.*[-\w]25,)/,因为它仍然非常简单,应该可以解决这些情况。

【讨论】:

我做了一些测试,看起来很棒!谢谢你。只是一个问题:这个数字 (25) 真的是 google docs id 的最小长度吗? 这在任何地方都没有记录。我只是从各种文件中获取了一堆 URL,查看最短的一个并给予折扣以防万一:) 还检查了 url 的另一部分是否远程接近 25 个直字符(中间没有点,等),所以它不会与其他部分混淆。 使用the regex suggested by aquadeep 不太可能进行不需要的匹配。然后使用 (group) 仅提取正则表达式的 ID 部分: url.match(/\/d\/(.25,)\//)[1]; @Kenigmatic,不需要的匹配似乎不太可能,我更愿意相信 25 个字符作为基本长度,而不是 ID 总是以数字开头。我还认为我们可以相信 ID 将始终由数字、字母和连字符组成。为什么要使用点? 刚刚发现您的编辑在最后一段中添加了一个不需要的“$”——不确定它应该在那里?猜猜我复制了哪一个并与之斗争:)。【参考方案2】:

我有一张表格,我在其中将 URL 放入单元格中,然后将其拉入 App 脚本以执行其他操作(例如在文件夹中创建包含表格内容的文档)。

我只是使用简单的str.split("/") 来提取 ID。有时,如果 URL 包含/u/0/,我只是将索引向下移动一点:

if (sheet.getRange("D2").getValue().split("/")[4] === "u") 
  folderId = sheet.getRange("D2").getValue().split("/")[7];
 else 
  folderId = sheet.getRange("D2").getValue().split("/")[5];

虽然它仅适用于两种给定的 Google Drive URL 格式。除了drive.google.com/drive/folders/#folderIddrive.google.com/drive/u/o/folders/#folderId,我还没有遇到很多其他人。

【讨论】:

【参考方案3】:

Henrique 建议的解决方案可能无法涵盖 Google 云端硬盘文件由 Google Workspace 用户共享且域可能是文件网址的一部分的情况。如果域名很长,则会捕获域名而不是文件 URL。

https://drive.google.com/a/thisisaverylongdomainname.org/file/d/1djf7XfuKx4Px55x7ahvMa5uznp3Ibe5vd7Y/view?usp=sharing

Google Drive 生成​​的文件 ID 不包含句点 (.),因此修改后的 RegEx 可以防止捕获域名。

function getFileIdFromDriveUrl(url) 
  var match = url.match(/([a-z0-9_-]25,)[$/&?]/i);
  return match ? match[1] : null;

【讨论】:

【参考方案4】:

如果您在电子表格的单元格中有指向 Google Drive 文件的 URL,我相信您可以使用以下公式提取 fileID:

=mid(cellAddress,33,33)

例子:

=mid(A2,33,33)

【讨论】:

【参考方案5】:

要从 url 电子表格中提取 id,我使用下面的代码。它适用于 Google 电子表格和云端硬盘中的 Excel。也许也适用于其他文档。

function getIdSheetFromUrl_(url)

    var id = url.split('id=')[1];
    if(!id)
    
        id = url.split('/d/')[1];
        id = id.split('/edit')[0]; // here we have the id
    
    return DriveApp.getFileById(id);

【讨论】:

【参考方案6】:

对于 Python:

对于固定长度的谷歌驱动器 ID,您可以使用:

regex = "([\w-])33|([\w-])19"
match = re.search(regex,url)

Google 云端硬盘使用 33 个字符用于普通硬盘,19 个字符用于团队硬盘

另一种不使用固定长度而是使用前置模式的方法:

regex = "(?<=/folders/)([\w-]+)|(?<=%2Ffolders%2F)([\w-]+)|(?<=/file/d/)([\w-]+)|(?<=%2Ffile%2Fd%2F)([\w-]+)|(?<=id=)([\w-]+)|(?<=id%3D)([\w-]+)"

match = re.search(regex,url)

【讨论】:

【参考方案7】:

现在可以在 Google Apps 脚本中使用 openByUrl 方法。

请参阅参考文档here for Sheets、here for Docs、here for Slides 和 here for Forms。

因为你写了:

我想获取文档 ID 以在 Google 云端硬盘上创建副本

...我假设您不需要 ID 本身。通过 URL 获取 sheet/doc/slide/form 后,可以进行复制。

【讨论】:

【参考方案8】:

我没有足够的声誉来评论接受的答案,但是当驱动器 URL 包含域名并且域名超过 25 个字符时,来自 Henrique G. Abreu 的接受的答案失败(只是很难找到这一点:)

否则它非常可靠,我认为是此处提供的最优雅和最强大的。

因此,扩展已接受的答案,以下正则表达式将获得至少 25 个字符长的单词字符或连字符字符串的最后一次出现,其前面紧跟一个不是非单词字符的字符或连字符,并且可选地后跟相同类型的字符,以及末尾可能出现的任何其他垃圾:

/.*[^-\w]([-\w]25,)[^-\w]?.*/

这失去了接受答案的特征,即仅在传递 ID 时它会起作用,但这不是我需要的用例。它适用于我测试过的文档和文件夹的所有不同类型的云端硬盘、文档、表格 URL。

【讨论】:

【参考方案9】:

还有一些上面没有提到的可以包含 ID 的 URL 扩展。

https://drive.google.com/drive/folders/ 和 https://drive.google.com/open?id= 和 https://drive.google.com/a/domain.edu.vn/folderview?id=

我想我会添加基于 this idea 的解决方案,涵盖上述两个扩展以及使用 /d/ 的扩展

function getIdFrom(url) 
  var id = "";
  var parts = url.split(/^(([^:\/?#]+):)?(\/\/([^\/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?/);
  if (url.indexOf('?id=') >= 0)
     id = (parts[6].split("=")[1]).replace("&usp","");
     return id;
    else 
   id = parts[5].split("/");
   //Using sort to get the id as it is the longest element. 
   var sortArr = id.sort(function(a,b)return b.length - a.length);
   id = sortArr[0];
   return id;
   
 

【讨论】:

【参考方案10】:

我只是想根据两个给定的答案添加我创建的函数,因为两者都不是我想要的。

function templateIdFrom(url) 
  var parts = url.match(/\/d\/(.+)\//);
  if (parts == null || parts.length < 2) 
    return url;
   else 
    return parts[1];
  

这将获取/d/ 之后的部分,直到下一个/,这就是文档 URL 始终包含其 ID 的方式。如果没有找到匹配项,那么我们只需返回原始参数,假定为 ID。

【讨论】:

【参考方案11】:

几乎所有 GoogleDrive/Docs 链接的 url 都是这样的,文件 ID 以这种模式“/d/XXXXXXXX/”出现:https://drive.google.com/file/d/0B3tB9BU9FRnpcTJmS2FoaktsQzA/view

使用下面的函数,我们可以得到'/d/fileid/',然后从开头截断'/d/',从结尾截断'/'。

public static string getIdFromUrl(string url)

    Regex r = new Regex(@"\/d\/(.+)\/", RegexOptions.IgnoreCase);
    Match m = r.Match(url);
    return m.ToString().TrimStart('/', 'd').Trim('/');

【讨论】:

以上是关于从 Google Apps 脚本上的 URL 获取文件 ID 的最简单方法的主要内容,如果未能解决你的问题,请参考以下文章

无法通过 Google Apps 脚本中的 YouTube 数据 API 从云端硬盘上传:空响应

无法通过 Google Apps 脚本中的 YouTube 数据 API 从云端硬盘上传:空响应

如何通过使用数组从 Google 表格中提取数据并格式化来优化 Apps 脚本代码?

如何从 Google 电子表格中的 Google Apps 脚本自动更新“站点地图”功能?

如何将 JSON 文件转换为使用 Google Apps 脚本分隔的新行?

如何获取显示#ERROR的单元格的后端值!使用 Google Apps 脚本?