问题描述
我正在使用Google Apps脚本和自定义函数来调用外部API来验证电话号码。
下面是我的函数的代码。
/**
* This CUSTOM FUNCTION uses the numVerify API to validate
* a phone number based on the input from JotForm and a
* country code which is derived from the JotForm country
*
* Numverify website: https://numverify.com/dashboard (account via LastPass)
* Numverify docs: https://numverify.com/documentation
*/
function PHONE_CHECK(number,country){
if(country == "")
return [["","country_not_set"]]
// check the API result has already been retrieved
var range = SpreadsheetApp.getActiveSheet().getActiveRange()
var apires = range.offset(0,1).getValue()
if(apires.length > 0)
return range.offset(0,1,2).getValues()
var url = 'http://apilayer.net/api/validate'
+ '?access_key=' + NUMVERIFY_KEY
+ '&number=' + encodeURIComponent(number)
+ '&country_code=' + encodeURIComponent(country)
+ '&format=1';
var response = UrlFetchApp.fetch(url,{'muteHttpExceptions': true});
var json = response.getContentText();
var data = JSON.parse(json);
if(data.valid !== undefined){
if(data.valid){
return [[data.international_format,"OK"]]
}else{
return [["","invalid_number"]] // overflows data to the next column (API Error) while keeping the phone field clear for import into TL
}
}else if(data.success !== undefined){
if(data.error.type.length > 0){
return [[number,data.error.type]]
}else{
return [[number,"no_error_type"]]
}
}else{
return [[number,"unexpected_error"]] // this generally shouldn't happen...
}
}
鉴于此公式(包含电话号码和国家/地区代码),它将根据numverify API检查电话号码,并将结果返回到单元格中并溢出到其右侧的单元格中。溢出用于指示是否已成功调用API,并检查结果是否已检索。
示例:
=PHONE_CHECK("+32123456789","BE")
请注意,第一个单元格为空,因为API返回了“无效的电话号码”代码。由于隐私原因,我不会在此处输入任何真实的电话号码。如果我要使用真实的电话号码,则第一个单元格将包含以国际号码格式设置的电话号码。
由于我使用的是免费计划,因此如果我已经知道结果是什么,我不想每次都重新运行该功能,因为我不想遇到速率限制。 不幸的是,这似乎不起作用,并且定期(每天一次),它将刷新工作表中每一行的结果。
有两个问题:
- 检查API结果然后退出函数时,我的逻辑有问题吗? (请参见下面的代码)
- 如果逻辑正确,为什么Google表格似乎会定期忽略(或刷新?)第二列中的值并以任何方式调用外部API?
var range = SpreadsheetApp.getActiveSheet().getActiveRange() // get the cell from which the function is called
var apires = range.offset(0,1).getValue() // get the values directly to the right of the cell
if(apires.length > 0) // check if there's anything there...
return range.offset(0,2).getValues() // return an array that basically just resets the same values,effectively stopping the script from running
解决方法
您的目标:
您想要一个自定义函数,也就是公式,只能运行一次,或运行一次以生成特定结果所需的次数。 您希望同一公式将值写入另一个单元格(例如相邻的单元格),以便将来告诉该公式是否应该再次运行。
简短答案:
恐怕从自定义函数AKA公式计算出的值是瞬态的,用它们无法实现您想要的操作。
说明:
您可以使用此自定义功能进行快速测试:
function arrayTest() {
return [[1,2,3,4,5]]
}
如果将其放在如下所示的单元格中:
您将看到,如果删除原始单元格中的公式,则溢出值也会消失。
因此,类似以下代码的内容将几乎始终产生相同的值:
function checkTest() {
var cell = SpreadsheetApp.getActiveRange()
var status = cell.offset(0,1).getValue();
if (status != "") {
return "already executed" // in your case without calling API
} else {
return [["OK","executed"]] // in your case making API call - will happen ~90% of the time.
}
}
// OUTPUT [["OK","executed"]]
在这里,我要插入一行并将其删除以强制重新计算公式。
在重新计算公式之前,Sheets要做的第一件事是清除公式填充的先前值。由于条件语句取决于其先前执行的值,因此它将始终评估为相同的结果。对于您而言,它几乎总是会进行API调用。
令人困惑的是,这不是100%可靠的!您会发现有时,它会按预期工作。尽管在我的测试中,这种情况只发生了十分之一,大约是10次,最常见的情况是在将更改保存到脚本编辑器时更新了公式。
理想情况下,尽管不可能,但您希望能够编写如下内容:
function checkTest() {
var cell = SpreadsheetApp.getActiveRange();
var cellValue = cell.getValue();
var adjacentCell = cell.offset(0,1);
var status = adjacentCell.getValue();
if (status == "") {
cell.setValue(cellValue)
adjacentCell.setValue("executed")
}
}
运行公式后会清除,clear setValue()
已禁用了公式!如果要使用setValue()
,则需要从菜单,触发器或脚本编辑器中运行脚本。在这种情况下,将其作为公式不再有意义。z
参考文献
https://developers.google.com/apps-script/guides/sheets/functions