2

我使用电子表格的一项长期技术是复制/粘贴特殊值 (C/PSV)。使用公式生成我感兴趣的值后,IC/PSV 然后可以删除源数据。

所以我写了一个使用这种技术的宏,但是单元格是空的。但是,如果我将宏一分为二,在 C/PSV 之前结束第一个宏,那么一切都会按预期进行。为什么是这样?有没有更好的方法来解决这个问题?这是我的三个宏。

function Step1() {
  var spreadsheet = SpreadsheetApp.getActive();
  var range = spreadsheet.getActiveRange();
  CopyRangeToNewSheet(spreadsheet, range);
  spreadsheet.getCurrentCell().offset(-1, 6).activate();
  FillInHeaders(spreadsheet);
  spreadsheet.getCurrentCell().offset(1, -4).activate();
  FillInFormulas(spreadsheet);
  spreadsheet.getCurrentCell().offset(0, -4, range.getNumRows(), 5).activate();
  spreadsheet.getCurrentCell().offset(0, 0, 1, 5).copyTo(spreadsheet.getActiveRange(), SpreadsheetApp.CopyPasteType.PASTE_NORMAL, false);
};

function Step2() {
  var spreadsheet = SpreadsheetApp.getActive();
  var keepers = spreadsheet.getRange('G:J');
  keepers.activate();
  keepers.copyTo(keepers, SpreadsheetApp.CopyPasteType.PASTE_VALUES, false);
  var discard = spreadsheet.getRange('A:F')
  discard.activate();
  spreadsheet.getActiveSheet().deleteColumns(discard.getColumn(), discard.getNumColumns());
};

function BothSteps() {
  var spreadsheet = SpreadsheetApp.getActive();
  var range = spreadsheet.getActiveRange();
  CopyRangeToNewSheet(spreadsheet, range);
  spreadsheet.getCurrentCell().offset(-1, 6).activate();
  FillInHeaders(spreadsheet);
  spreadsheet.getCurrentCell().offset(1, -4).activate();
  FillInFormulas(spreadsheet);
  spreadsheet.getCurrentCell().offset(0, -4, range.getNumRows(), 5).activate();
  spreadsheet.getCurrentCell().offset(0, 0, 1, 5).copyTo(spreadsheet.getActiveRange(), SpreadsheetApp.CopyPasteType.PASTE_NORMAL, false);
  var keepers = spreadsheet.getRange('G:J');
  keepers.activate();
  keepers.copyTo(keepers, SpreadsheetApp.CopyPasteType.PASTE_VALUES, false);
  var discard = spreadsheet.getRange('A:F')
  discard.activate();
  spreadsheet.getActiveSheet().deleteColumns(discard.getColumn(), discard.getNumColumns());
};

function FillInHeaders(spreadsheet) {
  spreadsheet.getCurrentCell().setValue('First Name');
  spreadsheet.getCurrentCell().offset(0, 1).activate();
  spreadsheet.getCurrentCell().setValue('Last Name');
  spreadsheet.getCurrentCell().offset(0, 1).activate();
  spreadsheet.getCurrentCell().setValue('Middle Name');
  spreadsheet.getCurrentCell().offset(0, 1).activate();
  spreadsheet.getCurrentCell().setValue('Email');
}

function FillInFormulas(spreadsheet) {
  spreadsheet.getCurrentCell().setFormulaR1C1('=find(" ",R[0]C[-2])');
  spreadsheet.getCurrentCell().offset(0, 1).activate();
  spreadsheet.getCurrentCell().setFormulaR1C1('=if(iserr(R[0]C[-1]),R[0]C[-3],mid(R[0]C[-3],1,R[0]C[-1]))');
  spreadsheet.getCurrentCell().offset(0, 1).activate();
  spreadsheet.getCurrentCell().setFormulaR1C1('=if(iserr(R[0]C[-2]),"",mid(R[0]C[-4],R[0]C[-2]+1,50))');
  spreadsheet.getCurrentCell().offset(0, 2).activate();
  spreadsheet.getCurrentCell().setFormulaR1C1('=R[0]C[-5]');
}

function CopyRangeToNewSheet(spreadsheet, range) {
  var newSheet = spreadsheet.insertSheet(1);
  spreadsheet.setActiveSheet(newSheet, true);  
  spreadsheet.getCurrentCell().offset(1, 0).activate();
  range.copyTo(spreadsheet.getActiveRange(), SpreadsheetApp.CopyPasteType.PASTE_NORMAL, false);
}

这是电子表格本身,带有主要选项卡、步骤 1 的结果、步骤 2 和组合步骤的结果: https ://docs.google.com/spreadsheets/d/1_nabq_mHuegz_eMIPPAlIgonv71Jh6OPi6qKzeNGGTI/edit?usp=sharing

4

2 回答 2

4

SpreadsheetApp.flush()可能是您的宏中缺少的步骤。基本上,Apps Script 在内部优化了读写,如果你不调用这个方法,它可以自由地按照它的方式做事。

在您当前将任务分为“宏 1”和“宏 2”的位置添加此内容应该可以解决问题:

...
  spreadsheet.getCurrentCell().offset(0, 0, 1, 5).copyTo(spreadsheet.getActiveRange(), SpreadsheetApp.CopyPasteType.PASTE_NORMAL, false);
  // Force formulas to calculate and pending writes to be written.
  SpreadsheetApp.flush();
  // Read formula results and save as values.
  var keepers = spreadsheet.getRange('G:J');
...

另一种方法是将脚本从录制的宏的“事务”方法压缩到批处理/高效“大图”视图,方法是使用setValues()而不是copyTo

...
  SpreadsheetApp.flush();
  var toKeep = spreadsheet.getRange('G:J');
  toKeep.setValues(toKeep.getValues());
  toKeep.getSheet().deleteColumns(1, toKeep.getColumn() - 1);
}

请注意,您仍然希望调用.flush().

于 2018-05-05T21:17:46.187 回答
1

面对类似的问题(例如,将计算结果从一个单元格区域复制到另一个区域,在该区域中我只需要没有公式的结果),使用{contentsOnly:true}而不是SpreadsheetApp.CopyPasteType.PASTE_VALUES完成这项工作。

于 2018-11-22T10:50:44.283 回答