Google Apps 脚本中的正则表达式执行时间限制如何工作?

How does the Regular expression execution time limit work in Google Apps Script?

TLDR:

这个任意的 RegExp 执行时间限制是多少,它有多长,什么时候适用(因为它并不同样适用于所有 Google Apps 脚本上下文)?另外,为什么在整个脚本已经有执行时间限制的情况下应用它?

完整 Post:

突然报错

"Error: Regular expression operation exceeded execution time limit."

在 Google Apps 脚本中。我在 运行 使用我创建的 Google 工作表上的自定义菜单设置函数时遇到了这个错误。这使得一个简短的 UI 请求使用输入电子表格 url,然后 运行 使用提供的 url(和电子表格)的函数。

我以前有运行这个函数并且工作正常,但现在我得到这个正则表达式时间限制错误。需要明确的是,此脚本远未达到脚本执行的最大时间限制,显然我的正则表达式太长了。我已经确定带有正则表达式的行(运行s 重复并且通常很好并且一直工作到这一点)没有明显的缺陷。这是一个很大的正则表达式,但文本不是很长。它在 217 个字符的文本上失败。

此外,我发现当我 运行 来自 Google Apps 脚本编辑器的等效函数(没有 UI,它只是调用这个来自我创建的 Google Apps 脚本库的相同功能)。需要明确的是,我确信工作执行中的变量和环境是相同的。它在 8 秒内完成,解析相同的文本,并使用相同的正则表达式。

这让我相信存在适用于正则表达式的任意时间限制,因为函数是从自定义菜单调用的,函数短暂使用 UI,或者函数调用库(或它们的某种组合)。

这个任意的 RegExp 执行时间限制是多少,它有多长,什么时候适用(因为它并不同样适用于所有 Google Apps 脚本上下文)?另外,为什么在整个脚本已经有执行时间限制的情况下应用它?

我在 Google 的 Google Apps 脚本文档中找不到任何提及此特定 error/time limit/quota 的内容。

明确地说,我已经检查过他们使用的 UI 脚本是否使用了正确的库版本(并且开发模式无论如何都处于打开状态,因此它使用的是最新版本)。我还通过控制台打印确认相同的函数是 运行 相同的变量,所以我知道唯一的区别是函数的调用方式。

这是在一个上下文中打破时间限制但在另一个上下文中没有打破时间限制的正则表达式,如果您出于某种原因需要它:

/[\s\<\>]*\d+\s*(?:(?:l\s*f|linear\s*feet|lin\s*feet|lin\s*ft)|(?:s\s*f|square\s*feet|sq\s*\ft|sq\s*feet|sq)|(?:ea|each))(?:[\s\,]*\S+){0,7}\s*\,\s*(?:(?:(?:(?:remove|removal|(?:(?:^|\s)+rem(?:\s|\.|\:|\-|$))|(?:(?:^|\s)+rmv(?:\s|\.|\:|\-|$))))|(?:(?:encapsulate|encapsulation|(?:^|\s)+encp?(?:ap)?(?:$|\s|\.|\-|\:)+|(?:^|\s)+cap(?:$|\s|\.|\-|\:)+|(?:^|\s)+enp(?:$|\s|\.|\-|\:)+|(?:^|\s)+seal(?:$|\s|\.|\-|\:)+))|(?:enclose)))/gi

MCVE:

这里有一些文本在一种情况下失败了,但在另一种情况下却没有:

Storage and Mechanical Room 6 adjacent to Stage- 6 month AHERA 15 EA ACPFI RMV <Category: 3> Note: Middle of ceiling, 5 damaged fittings. RMV all. 0 SF Fireproofing, Enclosure, Above ceiling tiles <Category: 3> See note

要重现失败的上下文,请在 Google Sheets 电子表格中,使用脚本编辑器(作为文档绑定脚本)创建自定义菜单,然后单击“测试”按钮。

容器绑定脚本代码:

function onOpen(e) {
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var ui = SpreadsheetApp.getUi();
  ui.createMenu('Test Menu').addItem('Test', 'testFun').addToUi();
}

function testFun() {
  var regExp = /[\s\<\>]*\d+\s*(?:(?:l\s*f|linear\s*feet|lin\s*feet|lin\s*ft)|(?:s\s*f|square\s*feet|sq\s*\ft|sq\s*feet|sq)|(?:ea|each))(?:[\s\,]*\S+){0,7}\s*\,\s*(?:(?:(?:(?:remove|removal|(?:(?:^|\s)+rem(?:\s|\.|\:|\-|$))|(?:(?:^|\s)+rmv(?:\s|\.|\:|\-|$))))|(?:(?:encapsulate|encapsulation|(?:^|\s)+encp?(?:ap)?(?:$|\s|\.|\-|\:)+|(?:^|\s)+cap(?:$|\s|\.|\-|\:)+|(?:^|\s)+enp(?:$|\s|\.|\-|\:)+|(?:^|\s)+seal(?:$|\s|\.|\-|\:)+))|(?:enclose)))/gi;
  var text = 'Storage and Mechanical Room 6 adjacent to Stage- 6 month AHERA 15 EA ACPFI RMV <Category: 3> Note: Middle of ceiling, 5 damaged fittings. RMV all. 0 SF Fireproofing, Enclosure, Above ceiling tiles <Category: 3> See note';
  text.match(regExp);
  Logger.log('This line will not be reached because of error');
}

在脚本编辑器中从容器绑定脚本中 运行ning testFun() 时也会失败。

要重现成功的执行上下文,请在脚本编辑器中创建一个独立的 google 应用程序脚本(不是来自电子表格)和 运行 testFun()

独立脚本代码:

function testFun() {
  var regExp = /[\s\<\>]*\d+\s*(?:(?:l\s*f|linear\s*feet|lin\s*feet|lin\s*ft)|(?:s\s*f|square\s*feet|sq\s*\ft|sq\s*feet|sq)|(?:ea|each))(?:[\s\,]*\S+){0,7}\s*\,\s*(?:(?:(?:(?:remove|removal|(?:(?:^|\s)+rem(?:\s|\.|\:|\-|$))|(?:(?:^|\s)+rmv(?:\s|\.|\:|\-|$))))|(?:(?:encapsulate|encapsulation|(?:^|\s)+encp?(?:ap)?(?:$|\s|\.|\-|\:)+|(?:^|\s)+cap(?:$|\s|\.|\-|\:)+|(?:^|\s)+enp(?:$|\s|\.|\-|\:)+|(?:^|\s)+seal(?:$|\s|\.|\-|\:)+))|(?:enclose)))/gi;
  var text = 'Storage and Mechanical Room 6 adjacent to Stage- 6 month AHERA 15 EA ACPFI RMV <Category: 3> Note: Middle of ceiling, 5 damaged fittings. RMV all. 0 SF Fireproofing, Enclosure, Above ceiling tiles <Category: 3> See note';
  text.match(regExp);
  Logger.log('This line will be successfully reached');
}

部分答案:

  • 此问题在 引擎中可重现。
  • 问题似乎无法在 引擎中重现

这似乎可以解释执行上下文的差异。鉴于 引擎已弃用,您不太可能找到问题的确切限制或原因(但它似乎在 300 毫秒左右)。