TLDR:
这个任意的 RegExp 执行时间限制是多少,它是多长时间,它何时适用(因为它在所有 Google Apps 脚本上下文中并不同样适用)?此外,当整个脚本已经存在执行时间限制时,为什么还要应用它?
全文:
我突然遇到了错误
“错误:正则表达式操作超出执行时间限制。”
在 Google Apps 脚本中。我在使用我创建的 Google 表格上的自定义菜单运行函数时遇到了这个错误。这会创建一个简短的 UI,请求使用输入电子表格 url,然后使用提供的 url(和电子表格)运行一个函数。
我之前运行过这个函数,它运行良好,但现在我得到这个正则表达式时间限制错误。需要明确的是,这个脚本远未达到脚本执行的最大时间限制,只是显然我的正则表达式太长了。我已经确定了正则表达式的行(它重复运行并且通常很好并且已经工作到这一点)没有明显的缺陷。这是一个很大的正则表达式,但文本不是很长。它在 217 个字符的文本上失败。
此外,当我从 Google Apps 脚本编辑器运行等效函数时,我发现错误不会发生(没有 UI,它只是从我创建的 Google Apps 脚本库中调用相同的函数)。需要明确的是,我确信工作执行中的变量和环境是相同的。它在 8 秒内完成,解析相同的文本,并使用相同的正则表达式。
这使我相信有一个任意时间限制适用于正则表达式,这适用于因为该函数已从自定义菜单调用,该函数短暂使用 UI,或者该函数调用了一个库(或这些的某种组合)。
这个任意的 RegExp 执行时间限制是多少,它是多长时间,它何时适用(因为它在所有 Google Apps 脚本上下文中并不同样适用)?此外,当整个脚本已经存在执行时间限制时,为什么还要应用它?
我无法在 Google 的 Google Apps 脚本文档中找到任何提及此特定错误/时间限制/配额的内容。
为了清楚起见,我检查了他们使用的 UI 脚本是否使用了正确的库版本(并且开发模式无论如何都处于打开状态,因此它使用的是最新版本)。我还确认通过控制台打印使用相同的变量运行相同的函数,所以我知道唯一的区别是函数的调用方式。
如果您出于某种原因需要它,这是在一种情况下打破时间限制但在另一种情况下没有时间限制的 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
MCVE:
以下是它在一种情况下失败但在另一种情况下失败的一些文本:
存储和机械室 6 与 Stage 相邻 - 6 个月 AHERA 15 EA ACPFI RMV <类别:3> 注意:天花板中间,5 个损坏的配件。全部RMV。0 SF 防火、外壳、天花板上方的瓷砖 <类别:3> 见注释
要重现失败的上下文,在 Google 表格电子表格中,使用脚本编辑器(作为文档绑定脚本)创建自定义菜单,然后单击“测试”按钮。
容器绑定脚本代码:
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');
}
testFun()
从脚本编辑器中的容器绑定脚本运行时,它也会失败。
要重现成功的执行上下文,请创建一个独立的 google apps 脚本(不是来自电子表格)并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');
}