使用脚本从 Google 表格中的活动单元格中删除命名范围

Deleting named ranges from active cells in google sheets with a script

提问人:Wim 提问时间:11/17/2023 最后编辑:Wim 更新时间:11/21/2023 访问量:49

问:

我是谷歌表格环境的新手,我对 VBA 的有限知识无济于事。我希望能够从谷歌表格上的“诅咒者”选择的一个单元格或多个单元格中删除范围名称。

我确实管理了从工作表中删除所有命名范围的代码,但这不是我想要的。您的帮助将不胜感激。

用红色圈出的活动单元格和命名范围进行说明

我希望脚本删除命名范围map_4bf9....在活细胞 C17 中。我希望能够选择范围 C17:H18,并让脚本从彼此相邻的所有单元格中删除命名范围。

要在谷歌表格中手动执行此操作,您将转到“数据/命名范围”,然后从右侧的列表中搜索范围名称,然后手动将其删除。

Google 表格选择命名范围

搜索并手动删除

删除工作表上所有命名区域的脚本如下:

函数 delRange(){ var namedRanges = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet().getNamedRanges(); for(i=0;i<namedRanges.length;i++){ namedRanges[i].remove(); } }

google-apps-script google-sheets named-ranges

评论

0赞 Yuri Khristich 11/17/2023
您的意思是重新定义命名范围(所有命名范围?)以从其中排除选定的单元格(它们)吗?
0赞 TheWizEd 11/18/2023
您建议如何运行此脚本。您可以使用触发器,但每次更改所选单元格时,它都会运行并干扰有效命名范围内更改的值。我的建议是从菜单项或按钮运行它。听起来怎么样?onSelectionChange(e)
0赞 Wim 11/18/2023
不,我想从选定的“活动”单元格中删除命名范围....未选择的单元格中的命名区域必须保留。在重新设计谷歌项目时,我将把它作为“appscript”运行。手动方法是转到“数据/命名范围/搜索”以查找命名范围,然后将其删除。非常漫长的过程。
1赞 TheWizEd 11/18/2023
你将无法做到这一点。不能删除名为 range 的多个单元格边界内的某个单元格。尝试一下,您不能创建非连续单元格的命名范围。它必须是单元格或矩形单元格块。
0赞 Tanaike 11/18/2023
关于,你能提供你目前的剧本吗?I did manage code deleting all named ranges from a sheet but that is not what i want.

答:

0赞 Cooper 11/19/2023 #1

这并不完全是你所要求的,但我相信它已经接近了。

原始数据图像:

enter image description here

活动范围的图像

enter image description here

运行代码后范围的图像:

enter image description here

function myFunk() {
  const ss = SpreadsheetApp.getActive();
  const sh = ss.getSheetByName("Sheet0");
  const remove = sh.getActiveRangeList();
  const rg = ss.getRangeByName('Array1');
  const row = rg.getRow();
  const col = rg.getColumn();
  let vs = rg.getValues();
  Logger.log('Before\n %s',JSON.stringify(vs).replace(/],/g,'],\n'));
  remove.getRanges().forEach(r => r.setValue(""));
  SpreadsheetApp.flush();
  vs = rg.getValues()
  Logger.log('After:\n %s',JSON.stringify(vs).replace(/],/g,'],\n'));
}

Execution log
9:01:23 AM  Notice  Execution started
9:01:23 AM  Info    Before
 [[17,20,26,0,10],
[10,31,22,24,4],
[19,31,16,1,29],
[3,5,17,22,8],
[15,0,30,11,30],
[7,5,23,10,3]]
9:01:23 AM  Info    After:
 [["",20,26,0,""],
[10,31,22,24,4],
[19,31,16,1,29],
[3,5,17,22,8],
[15,0,30,11,30],
["",5,23,10,""]]
9:01:25 AM  Notice  Execution completed

我认为这个版本更接近您可能正在寻找的版本,因为它只是更改数组中活动单元格的值,而没有实际更改范围内的值。

function myFunk() {
  const ss = SpreadsheetApp.getActive();
  const sh = ss.getSheetByName("Sheet0");
  const remove = breakUpRangeList(ss,sh,sh.getActiveRangeList());
  const rg = ss.getRangeByName('Array1');
  const row = rg.getRow();
  const col = rg.getColumn();
  let vs = rg.getValues();
  let bs = vs.slice();
  Logger.log('Before\n %s',JSON.stringify(vs).replace(/],/g,'],\n'));
  remove.getRanges().forEach(r => bs[r.getRow()-row][r.getColumn()-col] = "")
  Logger.log('After:\n %s',JSON.stringify(bs).replace(/],/g,'],\n'));
  return bs;
}

它需要这个辅助函数,它将 rangeLists 分解为单独的单个单元格范围列表

function breakUpRangeList(ss = SpreadsheetApp.getActive(), sh = ss.getSheetByName("Sheet0"), rgl) {
  let b = [];
  rgl.getRanges().forEach(rg => {
    rg.getValues().forEach((r, i) => {
      let row = rg.getRow() + i;
      r.forEach((c, j) => {
        let col = rg.getColumn() + j;
        b.push(sh.getRange(row, col).getA1Notation())
      })
    })
  })
  b = [...new Set(b)];
  //Logger.log(JSON.stringify(b));
  return sh.getRangeList(b);
}

使用与之前相同的命名范围,下面是活动范围的图像:

enter image description here

以下是此版本的执行日志:

Execution log
9:42:53 AM  Notice  Execution started
9:42:54 AM  Info    Before
 [[9,14,28,32,0],
[9,34,28,28,32],
[18,2,33,0,11],
[19,2,15,14,19],
[3,9,4,21,21],
[32,24,22,7,28]]
9:42:54 AM  Info    After:
 [["","",28,32,0],
["","",28,28,32],
["","",33,0,11],
[19,2,15,14,19],
[3,9,4,21,21],
[32,24,22,7,28]]
9:42:56 AM  Notice  Execution completed

请注意,原始区域或数组中的任何数据均未更改

我开始想,这可能是你想要的。它是缺少活动单元格的命名范围的 rangeList

function myFunk() {
  const ss = SpreadsheetApp.getActive();
  const sh = ss.getSheetByName("Sheet0");
  const remove = breakUpRangeList(ss, sh, sh.getActiveRangeList());
  const rg = ss.getRangeByName('Array1');
  const row = rg.getRow();
  const col = rg.getColumn();
  let vs = rg.getValues();
  let arr1 = vs.map((r, i) => r.map((c, j) => sh.getRange(i + row, j + col).getA1Notation())).flat();
  let arr2 = arr1.slice();
  remove.getRanges().forEach(r => { let idx = arr2.indexOf(r.getA1Notation()); if (~idx) { arr2.splice(idx, 1); } });
  Logger.log("arr2:\n %s",JSON.stringify(arr2));
  return sh.getRangeList(arr2);
}

我想就是这样。我想不出任何其他解决方法

评论

0赞 Wim 11/21/2023
谢谢你的努力....真的很感激。看起来此代码删除了单元格的内容,而不是基础命名区域。
0赞 Cooper 11/22/2023
不,不是基础命名范围。你并不总是得到你想要的,但有时如果你幸运的话,你会得到你需要的。