【问题标题】:Google Sheets script: return value if substring is within another columnGoogle表格脚本:如果子字符串在另一列中,则返回值
【发布时间】:2021-03-20 00:00:27
【问题描述】:

一般来说,我是 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));    
      }
    }

【问题讨论】:

  • 你怎么确定它会无限运行?此外,日志是开发人员最好的朋友 :-) Sheets / Google Apps Script 提供了几种日志记录方式,最容易用于调试的是 Apps Script execution log
  • 谢谢@somewhatsapient!它在 6 分钟后超时,并且工作表中只有 5225 行,所以我想它在某个地方循环。在调试时它永远不会遇到断点,并且执行日志完全是空的,除了标记它正在开始和结束。所以我根本没有线索,这很令人沮丧。
  • 除非您的代码比您在此处显示的内容更多,否则您没有设置任何断点,也没有包含任何日志记录语句。我建议在 for 循环中的最后一行之后添加一个断点,并可能创建一个变量来存储 .setValue() 操作的结果,然后记录 fnamefullname 和该变量。这样你就可以稍微窥探一下。
  • 我现在意识到 Apps Script 环境确实允许您在 UI 中设置断点 - 我指的是在代码中使用 debugger 语句。
  • @somewhatsapient 我认为它现在正在工作,由于某种原因,断点也是更新工作表所需的全部?非常感谢!!

标签: javascript excel search google-sheets


【解决方案1】:

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

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() 循环之后立即将所有包含值写入工作表。就性能而言,这是您可能会看到最大改进的地方。

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

【讨论】:

  • 非常感谢!我去看看!!
猜你喜欢
  • 2021-07-31
  • 1970-01-01
  • 2016-06-07
  • 2022-10-01
  • 2016-02-29
  • 2020-05-11
  • 1970-01-01
  • 2020-07-06
  • 1970-01-01
相关资源
最近更新 更多