当添加行并将结果复制到其他工作表时,Google工作表脚本就会运行

时间:2019-10-10 15:09:11

标签: google-apps-script google-sheets

我一直在运行一个脚本,该脚本通过与源数据不同的工作表上的函数将逗号分隔的数据拆分为新的行。数据量已经增长,并且计算将永远花费。

taking forever progress bar

示例电子表格在此处(包含少量数据): https://docs.google.com/spreadsheets/d/1e0YhJqHn62jju7KOOy5U2JZ5FLCv6_oeY-mc_jRF5-4/edit?usp=sharing

脚本如下:

function extract(range, colToSplit, delimiter) {
var resArr = [], row;
range.forEach(function (r) {
    r[colToSplit-1].replace(/(?:\r\n|\r|\n)(\d|\w)/g," , ").split(delimiter)
        .forEach(function (s) {
            row = [];
            r.forEach(function (c, k) {               
                row.push( (k === colToSplit-1) ? s.trim() : c);
            })
            resArr.push(row);
        })
})
return resArr;}

问题是,如何只针对新数据运行此脚本,然后将结果复制到其他“无公式的静态”工作表中,以确保脚本不会在所有数据都进行任何更改的情况下运行。

我对脚本之神表示崇高的敬意。

3 个答案:

答案 0 :(得分:0)

您可以使用脚本并通过编辑器或工作表中的按钮来触发脚本,而不是使用单元格功能。这样,您将受益于他们6分钟的时限(请参见the quotas)。

可以如此修改该函数,然后将其分配给一个按钮以作为onClick事件运行(有关此here的更多信息):

function extract() {
var resArr = [], row;
var colToSplit = 6;
var delimiter = " , ";
range = SpreadsheetApp.getActive().getSheets()[0].getDataRange().getValues();
range.forEach(function (r) {
    r[colToSplit-1].replace(/(?:\r\n|\r|\n)(\d|\w)/g," , ").split(delimiter)
        .forEach(function (s) {
            row = [];
            r.forEach(function (c, k) {               
                row.push( (k === colToSplit-1) ? s.trim() : c);
            })
            resArr.push(row);
        })
})
SpreadsheetApp.getActive().getSheets()[1].getRange(1, 1, resArr.length, resArr[0].length).setValues(resArr);
}

如果还有其他问题,请告诉我。

答案 1 :(得分:0)

您可以在边栏中非常简单地为函数创建html,如下所示:

function showButtonDialog() {
  var ss=SpreadsheetApp.getActive();
  var html='<input type="text" id="rng" /> Range<br /><input type="text" id="col" /> Column<br /><input type="text" id="dlm" /> Delimiter<br /><input type="button" value="run extract" onClick="extract();" />';
  html+='<script>function extract() {google.script.run.extract(document.getElementById("rng").value,document.getElementById("col").value,document.getElementById("dlm").value);}</script>';
  var userInterface=HtmlService.createHtmlOutput(html);
  SpreadsheetApp.getUi().showSidebar(userInterface);
}

这将测试您是否获得了正确的参数

function extract(a,b,c) {
  Logger.log('rng: %s col: %s del: %s',a,b,c);
}

您可能需要稍微调整一下功能。但是从代码的外观来看,您将不会有任何麻烦。

答案 2 :(得分:0)

我看到你不接受我以前的回答;我认为它不再符合您的目的。在这里,我提供了另一个解决方案,可以执行您最初的要求-仅处理新行。这可以通过使用Script Properties来实现。

请参阅下面的所有代码:

var COL_TO_SPLIT = 6;
var DELIMITER = " , ";
var NUM_COLUMNS = 16;

function extract(range, colToSplit, delimiter) {
  var resArr = [];
  range.forEach(function (r) {
    r[colToSplit-1].replace(/(?:\r\n|\r|\n)(\d|\w)/g," , ").split(delimiter)
      .forEach(function (s) {
          var row = [];
          r.forEach(function (c, k) {               
              row.push( (k === colToSplit-1) ? s.trim() : c);
          });
          resArr.push(row);
      });
  });
  return resArr;
}

function getCurrentRow() {
  var currentRow = PropertiesService.getScriptProperties().getProperty('currentRow');
  if (currentRow === null) {
    currentRow = 2;
  }
  return parseInt(currentRow);
}

function updateCurrentRow(newRow) {
  PropertiesService.getScriptProperties().setProperty('currentRow', newRow);
}

// Returns the new "currentRow"
function migrateRowsFrom(row) {
  var ss = SpreadsheetApp.getActive();
  var sourceSheet = ss.getSheetByName('Sheet1');
  var destinationSheet = ss.getSheetByName('Sheet2');

  var rowsToProcess = sourceSheet.getLastRow() - row + 1;
  if (rowsToProcess <= 0) return sourceSheet.getLastRow() + 1;
  var rows = sourceSheet.getRange(row, 1, rowsToProcess, NUM_COLUMNS).getDisplayValues();

  var extracted = extract(rows, COL_TO_SPLIT, DELIMITER);
  destinationSheet.getRange(destinationSheet.getLastRow() + 1, 1, extracted.length, extracted[0].length).setValues(extracted);

  return sourceSheet.getLastRow() + 1;
}

function update() {
  var lock = LockService.getDocumentLock();
  lock.waitLock(10000); // Wait (up to) 10s to acquire the lock

  var currentRow = getCurrentRow(); // currentRow is the row from which the script should run. i.e. if the last execution ended at row 2 (included), the value should be left to be 3. 1-indexed.
  var newCurrentRow = migrateRowsFrom(currentRow);
  updateCurrentRow(newCurrentRow);

  lock.releaseLock();
}

您必须调用的函数是update()。它将获取上次执行停止的行,处理尽可能多的行,然后更新该值,以便下一次执行知道从哪里开始。

请注意,这将从Sheet1中移出数据,进行处理,然后将其粘贴到Sheet2中。当然,您可以根据需要更改这些值。另外,请注意,您不应修改Sheet1值;因为它们已经被处理过,所以不会再次处理。

相关问题