function myFunction(range) {
var firstColumn = range.getColumn();
// loop over the range
}
一个单元格将使用以下内容引用它:
=myFunction(A1:A4)
问题是当我尝试执行此操作时,参数似乎只是将值传递给函数。因此,我不能使用任何Range方法,例如
getColumn()
。当我尝试这样做时,它出现以下错误:错误:TypeError:在对象1,2,3中找不到函数getColumn。
如何发送实际范围而不是仅将值发送到自定义函数之一?
#1 楼
因此,我经过长时间的努力寻找了一个好的答案,这就是我所发现的:未修改的range参数传递范围内的单元格值,而不是范围本身(如Gergely所述)
例如:执行此操作时,要先在字符串中传递范围(例如:
=myFunction(a1:a2)
),才能在函数中使用范围,然后使用函数内的以下代码将其转换为范围:Function myFunction(pRange){
var sheet = SpreadsheetApp.getActiveSpreadsheet();
var range = sheet.getRange(pRange);
}
最后,如果您希望传递范围的好处(例如智能地将范围引用复制到其他单元格),并且要将其作为字符串传递,则必须使用默认函数,该函数接受范围作为参数并输出可以使用的字符串。我详细介绍了以下两种方法,但我更喜欢第二种方法。
对于所有Google电子表格:
=myFunction("a1:a2")
对于新的Google表格:
=myFunction(ADDRESS(row(A1),COLUMN(A1),4)&":"&ADDRESS(row(A2),COLUMN(A2),4))
#2 楼
range
被视为javascript的2d数组。您可以使用range.length
获得行数,并使用range[0].length
获得列数。如果要从r
行和c
列中获取值,请使用:range[r][c]
。评论
我正在尝试找出范围内的第一列。例如,在范围C1:F1中,我想知道范围从C列开始。
–有道理
2010-12-24 23:38
@Senseful如果要在像= myFunction(C1:F1)这样的单元格中使用函数,则在函数range [0] [0]内将返回C1的值,range [0] [1]将返回C1的值D1的值,范围[0] [2]将返回E1的值,等等。
– Lipis
2010-12-25 13:20
我想我没有清楚地解释自己...看您对这个问题的回答。您建议我使用= weightedAverage(B3:D3,$ B $ 2:$ D $ 2),我想通过不必发送第二个参数(例如,我想将其称为= weightedAverage( B3:D3)),然后让代码自动知道范围从B开始到D结束,因此它从第二行获取相应的值。注意:值“ 2”可以硬编码,但“ B”不应硬编码。
–有道理
2010-12-25 19:26
@Senseful一般来说,我反对使用硬编码的东西,并且我认为加权平均值是否需要两个参数更为清楚。因此,如果您要进行硬编码,那么还有很多其他事情可以做。我现在找不到如何将B超出给定范围。我建议您仔细阅读入门指南(goo.gl/hm0xT),以了解如何使用范围和单元格。
– Lipis
2010-12-26 at 16:08
#3 楼
将Range
传递给Google电子表格函数时,框架会隐式执行paramRange.getValues()
,并且您的函数会以字符串,数字或对象的二维数组(例如Date
)接收Range中的值。Range
对象不是传递给自定义电子表格函数。下面的
TYPEOF()
函数将告诉您作为参数接收的数据类型。公式
=TYPEOF(A1:A4)
将这样调用脚本:
function calculateCell() { var resultCell= SpreadsheetApp.getActiveSheet().getActiveCell(); var paramRange= SpreadsheetApp.getActiveSheet().getRange('A1:A4'); var paramValues= paramRange.getValues(); var resultValue= TYPEOF(paramValues); resultCell.setValue(resultValue); }
function TYPEOF(value) { if (typeof value !== 'object') return typeof value; var details= ''; if (value instanceof Array) { details+= '[' + value.length + ']'; if (value[0] instanceof Array) details+= '[' + value[0].length + ']'; } var className= value.constructor.name; return className + details; }
#4 楼
可以做到的。可以通过在活动单元格(包含公式的单元格)中解析公式来获得对传递范围的引用。这假定自定义函数是单独使用的,而不是作为更复杂的表达式的一部分使用的:例如=myfunction(A1:C3)
而不是=sqrt(4+myfunction(A1:C3))
。 此函数返回所传递范围的第一列索引。
function myfunction(reference) {
var sheet = SpreadsheetApp.getActiveSheet();
var formula = SpreadsheetApp.getActiveRange().getFormula();
var args = formula.match(/=\w+\((.*)\)/i)[1].split('!');
try {
if (args.length == 1) {
var range = sheet.getRange(args[0]);
}
else {
sheet = ss.getSheetByName(args[0].replace(/'/g, ''));
range = sheet.getRange(args[1]);
}
}
catch(e) {
throw new Error(args.join('!') + ' is not a valid range');
}
// everything so far was only range extraction
// the specific logic of the function begins here
var firstColumn = range.getColumn(); // or whatever you want to do with the range
return firstColumn;
}
评论
我认为这篇文章也回答了关于Stack Overflow的以下问题:将单元格引用传递给电子表格函数
–鲁本♦
16年6月8日在3:37
您可以将args行替换为:var args = formula.match(/ myfunction + \((。*)\)/ i)[1] .split(', '); args = args.map(arg => arg.trim());
– catchdave
20 Sep 24'2:32
#5 楼
我在user79865的答案中扩展了这个绝妙的主意,以使其适用于更多情况,并向自定义函数传递了多个参数。要使用它,请复制以下代码,然后在自定义中函数调用
GetParamRanges()
像这样,并为其传递函数名称:function CustomFunc(ref1, ref2) {
var ranges = GetParamRanges("CustomFunc"); // substitute your function name here
// ranges[0] contains the range object for ref1 (or null)
// ranges[1] contains the range object for ref2 (or null)
... do what you want
return what_you_want;
}
下面是返回单元格颜色的示例:
/**
* Returns the background color of a cell
*
* @param {cell_ref} The address of the cell
* @return The color of the cell
* @customfunction
*/
function GetColor(ref) {
return GetParamRanges("GetColor")[0].getBackground();
}
以下是代码和更多说明:
/**
* Returns an array of the range object(s) referenced by the parameters in a call to a custom function from a cell
* The array will have an entry for each parameter. If the parameter was a reference to a cell or range then
* its array element will contain the corresponding range object, otherwise it will be null.
*
* Limitations:
* - A range is returned only if a parameter expression is a single reference.
* For example,=CustomFunc(A1+A2) would not return a range.
* - The parameter expressions in the cell formula may not contain commas or brackets.
* For example, =CustomFunc(A1:A3,ATAN2(4,3),B:E) would not parse correctly.
* - The custom function may not appear more than once in the cell formula.
* - Sheet names may not contain commas, quotes or closing brackets.
* - The cell formula may contain white space around the commas separating the custom function parameters, or after
* the custom function name, but not elsewhere within the custom function invocation.
* - There may be other limitations.
*
* Examples:
* Cell formula: =CUSTOMFUNC($A)
* Usage: var ranges = GetParamRanges("CustomFunc");
* Result: ranges[0]: range object for cell A1 in the sheet containing the formula
*
* Cell formula: =CUSTOMFUNC(3, 'Expenses'!B7)
* Usage: var ranges = GetParamRanges("CustomFunc");
* Result: ranges[0]: null
* ranges[1]: range object for cell B7 in sheet Expenses
*
* Cell formula: =sqrt(4+myfunction(A1:C3))
* Usage: var ranges = GetParamRanges("MyFunction");
* Result: ranges[0]: range object for cells A1 through C3 in the sheet containing the formula
*
* Cell formula: =CustomFunc(A1+A2, A1, A2)
* Usage: var ranges = GetParamRanges("CustomFunc");
* Result: ranges[0]: null
* ranges[1]: range object for cell A1 in the sheet containing the formula
* ranges[2]: range object for cell A2 in the sheet containing the formula
*
* @param {funcName} The name of the custom function (string, case-insensitive)
* @return The range(s) referenced by the parameters to the call
*/
function GetParamRanges(funcName) {
var ourSheet = SpreadsheetApp.getActiveSheet();
var formula = SpreadsheetApp.getActiveRange().getFormula();
var re = new RegExp(".+" + funcName + "\s*\((.*?)\)","i");
var ranges=[]; // array of results
try {
var args = formula.match(re)[1].split(/\s*,\s*/) // arguments to custom function, separated by commas
// if there are no args it fails and drops out here
for (var i=0; i<args.length; i++) {
var arg=args[i].split('!'); // see if arg has a sheet name
try {
if (arg.length == 1) { // if there's no sheet name then use the whole arg as the range definition
ranges[i] = ourSheet.getRange(arg[0]);
}
else { // if there's a sheet name, use it (after removing quotes around it)
var sheetName=arg[0].replace(/'/g, '');
var otherSheet=SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetName);
ranges[i] = otherSheet.getRange(arg[1]);
}
}
catch(e) { // assume it couldn't be identified as a range for whatever reason
ranges[i]=null;
}
}
}
catch(e) {}
return ranges
}
评论
一点也不差,但是请指出,这使假设custion函数仅在公式中使用一次。 F.i.我必须使用以下论坛:= CountCcolor(B5:B38,$ A40)/ 2 + CountCcolor(B5:B38,$ A41)/ 2 + CountCcolor(B5:B38,$ A42)/ 2 + CountCcolor(B5:B38, $ A43)/ 2 + CountCcolor(B5:B38,$ A44)/ 2从我的理解来看,这种方式行不通。如果我们解决它能够处理这个问题,那就太好了。
– haemse
19-09-12在11:01
#6 楼
作为替代方法,受@Lipis注释的启发,您可以使用行/列坐标作为附加参数来调用函数:=myFunction(B1:C2; ROW(B1); COLUMN(B1); ROW(C2); COLUMN(C2))
在这种形式下,公式可以轻松地复制(或拖动)到其他单元格中,并且将自动调整单元格/范围引用。
您的脚本功能需要这样更新:
function myFunction(rangeValues, startRow, startColumn, endRow, endColumn) {
var range = SpreadsheetApp.getActiveSheet().getRange(startRow, startColumn, endRow - startRow + 1, endColumn - startColumn + 1);
return "Range: " + range.getA1Notation();
}
请注意,
getRange
函数采用startRow
,startColumn
,然后采用行数和列数-而不是结束行和结束列。因此,算术。评论
那是我期望的确切答案。行和列。
–陈建武
19年6月23日在6:02
#7 楼
我通过Google Apps脚本区分了Google Spreadsheet中的两个不同的自定义函数:一个需要API的函数; SpreadsheetApp,(示例)
不进行任何调用的,(示例)
第一个功能几乎可以执行任何操作。除了调用电子表格服务外,它还可以调用GmailApp或Google提供的任何服务。 API调用将减慢该过程。可以传递范围或通过函数检索范围,以访问所有可用的方法。
第二个功能仅限于“电子表格”。在这里,人们可以利用JavaScript来重新处理数据。这些功能通常非常快。传递的范围不过是包含值的2D数组。
在您的问题中,您首先需要调用
.getColumn()
方法。如上所述,这清楚地表明您需要1类自定义函数。 有关如何设置电子表格和表格以及创建自定义功能的信息,请参见以下答案。
#8 楼
几个月前,我正在研究此问题,并提出了一个非常简单的想法:创建一个新表格,以每个单元格的名称为内容:单元格A1看起来像:
= arrayformula(cell("address",a1:z500))
将工作表命名为“ Ref”。
然后,当需要引用单元格作为字符串而不是内容的引用时,请使用:
= some_new_function('Ref'!C45)
当然,您需要检查该函数是否传递了字符串(一个单元格)或一维或二维数组。如果得到一个数组,它将具有所有单元格地址作为字符串,但是从第一个单元格以及宽度和高度,您可以弄清楚所需的内容。
#9 楼
我整个上午一直在努力,并看到上述非答案讨论内容的证据。有理智的我都想要传递的单元格的地址,而不是值。答案很简单。无法完成。我发现了一些变通办法,它们依赖于找出哪个单元格包含公式。很难说这是否会对以上Senseful有帮助。所以我在做什么?
The data.
[A] [B] [C] [D] [E] [F] [H]
[1] Name Wins Losses Shots Points Fouls Most recent
WL Ratio
[2] Sophia 4 2 15 7 1 0
[3] Gloria 11 3 11 6 0 0
[4] Rene 2 0 4 0 0 0
[5] Sophia 7 4 18 9 1 1.5
H列是Sophia的(胜利-PrevWins)/(损失-PrevLosses)
(7-4 )/(4-2)= 1.5
,但是我们不知道Sophia以前出现在哪一行。
如果将A硬编码为名称列,则可以全部使用VLOOKUP来完成。 。
在VLOOKUP之后,我得到了一些#NA(找不到名称)和#DIV0(分母为零),并用= IF(IF(...))包裹起来,以在这些情况下显示更多可口的文本。 br />现在我的表情非常笨拙,笨拙且难以维护。所以我想要宏扩展(不存在)或自定义函数。
但是当我创建一个辅助对象SubtractPrevValue(cell)时,它接收的是“ 7”而不是B5。
没有内置的方法可以从传递的参数中获取单元格或范围对象。
如果我让用户用手工输入双引号的单元格名称,那么我可以做到...
SubtractPrevValue(“ B5”)。但这确实阻碍了复制/粘贴和相对单元格功能。
但是后来我找到了解决方法。
SpreadsheetApp.getActiveRange()是包含公式的单元格。
这就是我真正需要知道的全部。行号。
下面的函数获取一个NUMERIC列号,并减去该列中的上一个匹配项。真的很慢。在显示“ Thinking ...”(思考...)时延迟一到两秒钟,所以我回到了难以理解的,难以维护的工作表公式。
#10 楼
除了提供“ Range”对象之外,Google Developers几乎传递了一个随机数据类型。因此,我开发了以下宏来打印输入的值。function tp_detail(arg)
{
var details = '';
try
{
if(typeof arg == 'undefined')
return details += 'empty';
if (typeof arg !== 'object')
{
if (typeof arg == 'undefined')
return details += 'empty';
if (arg.map)
{
var rv = 'map: {';
var count = 1;
for (var a in arg)
{
rv += '[' + count + '] ' + tp_detail(a);
count = count + 1;
}
rv += '}; '
return rv;
}
return (typeof arg) + '(\'' + arg + '\')';
}
if (arg instanceof Array)
{
details += 'arr[' + arg.length + ']: {';
for (var i = 0; i < arg.length; i++)
{
details += '[' + i + '] ' + tp_detail(arg[i]) + ';';
}
details += '} ';
}
else
{
var className = arg.constructor.name;
return className + '(' + arg + ')';
}
}
catch (e)
{
var details = '';
details = 'err : ' + e;
}
return details;
}
#11 楼
创建函数并通过范围作为参数:function fn(input) {
var cell = SpreadsheetApp.getActiveSpreadsheet().getSheets()[0].getRange(SpreadsheetApp.getActiveRange().getFormula().match(/=\w+\((.*)\)/i)[1].split('!'));
// above ... cell is "range", can convert to array?
var sum=0;
for (var i in cell.getValues() ){
sum = sum + Number(cell.getValues()[i]);
}
return sum;
}
电子表格中的用法:
=fn(A1:A10)
它将显示值如
sum(A1:A10)
。#12 楼
我整理了以前的答案**
*
* @customfunction
**/
function GFR(){
var ar = SpreadsheetApp.getActiveRange();
var as = SpreadsheetApp.getActive();
return ar.getFormula()
.replace(/=gfr\((.*?)\)/i, '')
.split(/[,;]/)
.reduce(function(p, a1Notation){
try{
var range = as.getRange(a1Notation);
p.push(Utilities.formatString(
'Is "%s" a Range? %s',
a1Notation,
!!range.getDisplayValues
));
} catch(err){
p.push([a1Notation + ' ' + err.message]);
}
return p;
},[]);
}
它使用当前公式并检查它是否为范围。
=GFR(A1:A5;1;C1:C2;D1&D2)
返回|Is "A1:A5" a Range? true|
|1 Range not found |
|Is "C1:C2" a Range? true|
|D1&D2 Range not found |
对于TC的完整组成,可以调用类似的名称
var range = as.getRange(a1Notation);
var column = range.getColumn();
评论
救生员。可以,谢谢。
–贾斯汀·帕维森(Jithin Pavithran)
18年11月27日在4:57
@EmersonFarrugia我指的是当您将函数从一个单元格复制到另一个单元格时,Google表格可以自动更新相对单元格引用的功能
–内森·汉娜(Nathan Hanna)
19年4月13日在18:02