【问题标题】:Programmatically test if a Google Sheet cell is in a named range以编程方式测试 Google 表格单元格是否在命名范围内
【发布时间】:2020-04-01 16:01:44
【问题描述】:

我正在编写一个 Google 表格 onEdit() 触发器,它只需要在任何已编辑的单元格位于电子表格的指定范围内时执行某些操作。

我有这个:

function onEdit(e) {
  var editRange = e.range;

  var numRows = editRange.getNumRows();
  var numCols = editRange.getNumColumns();

  for (var i = 1; i <= numRows; i++) {
    for (var j = 1; j <= numCols; j++) {
      var cell = editRange.getCell(i,j);

      if (isInRange(cell, myNamedRange)) {
         /* Do something clever */
      }
    }
  }
}

但是我在编写isInRange() 函数时遇到了麻烦。感觉应该是内置的电子表格功能,但我找不到任何看起来可能的东西。

更新:一夜之间让我觉得可能有更简单的方法。我真正需要的是两个范围之间的交集。

【问题讨论】:

  • 我注意到您刚刚更新了您的答案。在您的脚本中,当编辑多个单元格时,每个单元格都由if (isInRange(cell, myNamedRange)) {} 检查truefalse。所以我提出了示例脚本。但我深表歉意,我的回答没有用。从您更新的问题中,虽然我不确定我是否能正确理解您的目标,但我又添加了一个示例脚本。你能确认一下吗?如果我误解了您的目标并且这不是您想要的方向,我深表歉意。
  • @Tanaike:不,我确实认为您的原始解决方案很有帮助。谢谢你。现在才凌晨,我还没有真正开始:-)
  • @Tanaike:我添加了我的更新,因为我认为它可能有用。我想知道是否有内置的“两个范围的交集”功能。但是,现在看了,一个也看不到。所以我会回到你原来的解决方案。
  • 感谢您的回复。不幸的是,在当前阶段,没有内置方法可以直接检索两个范围的交集范围。如果尝试实现此功能,我认为该示例可能类似于我的答案中的示例脚本。检查一个单元格的脚本很简单。但是检查多个单元格的脚本有点复杂。如果示例脚本有用,我很高兴。

标签: google-apps-script google-sheets


【解决方案1】:
  • 您想检查一个单元格是否包含在命名范围内。
  • 你要创建isInRange的函数。
  • 您希望使用 Google Apps 脚本实现此目的。

流程:

isInRange的流程如下。

  1. 检索活动工作表中的命名范围。
  2. 使用myNamedRange 检索命名范围。
  3. cellmyNamedRange 的命名范围内时,返回true
  4. cell 不在myNamedRange 的命名范围内时,返回false
  5. 找不到myNamedRange 时出错。

示例脚本:

function isInRange(cell, myNamedRange) {
  var sheet = SpreadsheetApp.getActiveSheet();
  var namedRanges = sheet.getNamedRanges();
  for (var i = 0; i < namedRanges.length; i++) {
    var nr = namedRanges[i];
    if (nr.getName() == myNamedRange) {
      var range = nr.getRange();
      var startRow = range.getRow();
      var endRow = startRow + range.getNumRows() - 1;
      var startColumn = range.getColumn();
      var endColumn = startColumn + range.getNumColumns() - 1;
      return cell.getRow() >= startRow && cell.getRow() <= endRow && cell.getColumn() >= startColumn && cell.getColumn() <= endColumn;
    }
  }
  throw new Error(myNamedRange + " was not found.");
}
  • isInRange这个示例脚本用于你的onEdit时,当cellmyNamedRange的命名范围内时,if (isInRange(cell, myNamedRange)) {}的if语句为true

注意:

  • 在此示例脚本中,命名范围是从活动工作表中检索的。如果你想改变这个,请修改脚本。

参考资料:


补充:

  • 您想要检索两个范围的交集范围。
    • 例如,当命名范围和输入范围分别为“A1:B3”和“B3:C4”时,您希望检索“B3”作为交集范围。

此示例脚本的流程如下。

流程:

  1. 从“inputRange”中检索 a1Notations。
  2. 从“myNamedRange”中检索 a1Notations。
  3. 检索交叉点范围。

在此示例脚本中,结果值返回一个包含 a1Notations 的数组。因为输入范围可能不连续,而当a1Notations的数组也可以用于RangeList

示例脚本:

function myFunction() {
  var myNamedRange = "sampleNamedRange";  // Please set the name of the named range.
  var inputRange = SpreadsheetApp.getActiveSheet().getRange("B3:C4");  // Please set the range.


  var columnToLetter = function(column) { // <--- https://stackoverflow.com/a/21231012/7108653
    var temp, letter = '';
    while (column > 0) {
      temp = (column - 1) % 26;
      letter = String.fromCharCode(temp + 65) + letter;
      column = (column - temp - 1) / 26;
    }
    return letter;
  };

  var result = [];
  var sheet = SpreadsheetApp.getActiveSheet();
  var namedRanges = sheet.getNamedRanges();
  for (var i = 0; i < namedRanges.length; i++) {
    var nr = namedRanges[i];
    if (nr.getName() == myNamedRange) {
      // Retrieve a1Notations from "inputRange".
      var iStartRow = inputRange.getRow();
      var iEndRow = iStartRow + inputRange.getNumRows() - 1;
      var iStartColumn = inputRange.getColumn();
      var iEndColumn = iStartColumn + inputRange.getNumColumns() - 1;
      var irA1Notations = [];
      for (var j = iStartRow; j <= iEndRow; j++) {
        var temp = [];
        for (var k = iStartColumn; k <= iEndColumn; k++) {
          temp.push(columnToLetter(k) + j);
        }
        Array.prototype.push.apply(irA1Notations, temp);
      }
      
      // Retrieve a1Notations from "myNamedRange".
      var namedRange = nr.getRange();
      var nStartRow = namedRange.getRow();
      var nEndRow = nStartRow + namedRange.getNumRows() - 1;
      var nStartColumn = namedRange.getColumn();
      var nEndColumn = nStartColumn + namedRange.getNumColumns() - 1;
      var nrA1Notations = {};
      for (var j = nStartRow; j <= nEndRow; j++) {
        for (var k = nStartColumn; k <= nEndColumn; k++) {
          nrA1Notations[columnToLetter(k) + j] = null;
        }
      }
      
      // Retrieve intersection ranges.
      result = irA1Notations.filter(function(e) {return nrA1Notations.hasOwnProperty(e)});
    }
  }
  
  Logger.log(result)
}

【讨论】:

    【解决方案2】:

    我接受了Tanaike's answer,因为它给了我很多线索,我在处理这个问题时发现这些线索很有用。但是,实际上,正如我在今天早上的问题更新中提到的那样,我最终编写了一个 rangeIntersection() 函数。

    代码在这里,以防其他人发现它有用。

    function rangeIntersection(range1, range2) {
      var sheet1 = range1.getSheet();
      var sheet2 = range2.getSheet();
    
      if (sheet1.getSheetId() !== sheet2.getSheetId()) {
        return false;
      }
    
      if (range1.getLastColumn() < range2.getColumn() ||
          range1.getColumn() > range2.getLastColumn() ||
          range1.getLastRow() < range2.getRow() ||
          range1.getRow() > range2.getLastRow()) {
        return false;
      }
    
      var intersectRange = sheet1.getRange(
        Math.max(range1.getRow(), range2.getRow()),
        Math.max(range1.getColumn(), range2.getColumn()),
        Math.min(range1.getLastRow(), range2.getLastRow()) - Math.max(range1.getRow(), range2.getRow()) + 1,
        Math.min(range1.getLastColumn(), range2.getLastColumn()) - Math.max(range1.getColumn(), range2.getColumn()) + 1,
      );
    
      return intersectRange;
    }
    

    【讨论】:

    • 谢谢 - 我正在尝试做与您完全相同的事情(查看 event.range 是否属于事件处理程序中工作表的命名范围之一),这是完美的。
    • 很好的答案,我想补充一点,您可以为每个变量提取变量以避免多次调用相同的函数并加快执行速度,即var range2Col = range2.getColumn()
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-08-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-05
    • 2018-07-23
    相关资源
    最近更新 更多