首页 > 解决方案 > Google表格脚本:如果子字符串在另一列中,则返回值

问题描述

一般来说,我是 Javascript/Sheets/scripts 的新手(阅读:现在只是第一次看 JS),所以请原谅我这是多么基本。我做了很多独立的研究,但没有运气。

我有一个电子表格,其中包含一个全名列(全部大写 - LAST、FIRST 格式),分成 LAST 和 FIRST 两个附加列(全名通过逗号分隔),然后是一个包含全名的小写列以 First Last 格式的人。

数据中存在一些错误 - 例如,LAST、FIRST 后面可能跟有完全不同的名称的 First Last,或者前一列的拼写错误。我基本上是在内容不匹配时尝试标记它,无论是拼写还是整体名称。

我编写了这个简单的脚本,它以 First Last 格式(F 列)提取名字(D 列)和全名,并检查全名中是否包含名字。假设它应该返回 G 列中 search() 的值。这样我可以使用条件格式来标记任何 #VALUE!从失败的搜索中出现,表示需要检查该行。

不幸的是,脚本无限运行,我无法弄清楚为什么我无法打断点并实际返回实际工作表中相应列中的值。这是一个很小的项目,我正在努力证明从头开始学习脚本和表格之间的界面是合理的,所以我非常感谢一些帮助!谢谢!

   function checkName() {
      var s = SpreadsheetApp.getActiveSheet();
      var data = s.getDataRange().getValues();
      var data_len = data.length;
      for(var i=6; i<data_len; i++) {
        var fname = SpreadsheetApp.getActiveSheet().getRange(i, 4).getValue();
        var fullname = SpreadsheetApp.getActiveSheet().getRange(i, 6).getValue();
        s.getRange(i, 7).setValue(fullname.includes(fname));    
      }
    }

标签: javascriptexcelsearchgoogle-sheets

解决方案


以下是我如何编写一个函数来满足您的要求:

function checkName() {

  // these two will be used in an Array,
  // which is 0-indexed
  const FIRST_NAME_COLUMN = 3; 
  const FULL_NAME_COLUMN = 5;

  // these two will be used in a Sheets range,
  // which is 1-indexed
  const INCLUDES_COLUMN = 7;
  const FIRST_ROW = 6;

  const s = SpreadsheetApp.getActiveSheet();
  const sheetDataRange = s.getDataRange(); // this is just the whole shebang

  // get the dimensions of the main range
  const RANGE_HEIGHT = sheetDataRange.getHeight();
  const RANGE_WIDTH = sheetDataRange.getWidth();
  
  // use your first row number to constrain the actual data range
  // we'll use this reference to create an array we can easily iterate over
  const dataRange = s.getRange( FIRST_ROW, 1, RANGE_HEIGHT, RANGE_WIDTH );

  // data is a 2-dimensional Array,
  // so you could get values like data[row][column]
  // Also, Arrays are 0-indexed, so every number is 1 less than you had originally
  const data = dataRange.getValues(); 

  Logger.log( data ); // just to inspect

  const includesArray = [];

  for (const row of data) {
    // using a for ... of loop means we don't have to track the index,
    // and we can treat each row as a 1-D array inside the loop
    const firstName = row[FIRST_NAME_COLUMN];
    const fullName = row[FULL_NAME_COLUMN];
    const included = fullName.includes(firstName); // btw this will return a value of TRUE for ones that do include and FALSE for those that don't

    Logger.log( `${firstName}, ${fullName}, ${included}` );
    // debugger;
    includesArray.push( [included] ); // adding an Array that includes just the single element, since that represents a single data column
  }

  Logger.log( includesArray );
  debugger;

  s.getRange( FIRST_ROW, INCLUDES_COLUMN, RANGE_HEIGHT, 1 ).setValues( includesArray );

}

const尽可能使用,用于范围界定并表明我不会重新分配变量。我还为 THESE_CONSTANTS 分配了幻数,因此它们在代码中具有一些语义含义(这只是为了我的理智)。

另外,我根本没有触及循环内的“数据库”——我在这里严格使用 JS 数组。我已经从工作表中提取了数据dataRange.getValues(),然后我在循环之后立即将所有包含值写入工作表setValues()。这是您可能会在性能方面看到最佳改进的地方。

试一试,并提出您需要的任何问题!


推荐阅读