搜索Google Sheet列以查找匹配的文本和打印匹配项

时间:2016-04-23 12:51:23

标签: google-sheets

我在A栏中有一个长词,如'谴责'和'收入',以及B栏中的'Con'和'Come'等短词。

我想在右边创建一个单元格,如果它包含“SHORTER WORD”列的文本并将它们打印成一对,将搜索“LONG WORD”列。

我只需要它返回它遇到的第一个实例。

我已经查看了各种MATCH和LOOKUP命令,但似乎没有人能够“从整列中返回一个匹配的单词”。

由于

塔迪

4 个答案:

答案 0 :(得分:1)

我已经为你整理了一个基于脚本的解决方案。其他解决方案需要在您可能有部分的每一行上都有一个公式,最终会导致大量数据集陷入困境。这应该在几秒钟之后为数据行数万行生成一系列匹配。

注意:由于您选择不提供样本数据集,因此我不得不假设它是如何布局的。但是,无论您的列位于何处,只要标题为Full WordsPartialsMatches,这都可以使用。

链接到电子表格(必须登录Google帐户才能使用该按钮):Google Sheet

只需点击Get Matches按钮即可生成匹配项。

源代码比它需要的更复杂/更动态,但我已经有一堆功能已经存在,我只是重复使用。

<强>来源:

//Retrieves all the necessary word matches
function GetWordMatches() {
  var spreadsheet = SpreadsheetApp.openById('1s0S2iJ7L0wEXgVsKrpuK-aLysaxfHYRDQgp3ShPR8Ns').getSheetByName('Matches');
  var dataRange = spreadsheet.getDataRange();
  var valuesRange = dataRange.getValues(); 
  var columns = GetColumns(valuesRange, dataRange.getNumColumns(), 0);

  var fullWordsData = GetColumnAsArray(valuesRange, columns.columns['Full Words'].index, true, 1);
  var partialsArray = GetColumnAsArray(valuesRange, columns.columns['Partials'].index, true, 1);
  var partialsData = GeneratePartialsRegexArray(partialsArray);

  var matches = GenerateMatches(fullWordsData, partialsData); 

  WriteMatchesToSheet(spreadsheet, columns.columns['Matches'].index, matches, partialsArray);  
}

//Writes the matches to the sheet
function WriteMatchesToSheet(spreadsheet, matchesColumnIndex, matches, partialsArray){
  var sortedMatches = SortByKeys(matches, partialsArray);
  var dataRange = spreadsheet.getRange(2, matchesColumnIndex+1, sortedMatches.length);
  dataRange.setValues(sortedMatches);
}

//Generates an array of matches for the full words and partials
function GenerateMatches(fullwordsData, partialsData){
  var output = [];
  var totalLoops =  0;

  for(var  i = 0; i < fullwordsData.length; i++){
    totalLoops++;
    for(var ii = 0; ii < partialsData.length; ii++){
      totalLoops++;
      var result = fullwordsData[i].match(partialsData[ii].regex)
      if(result){
        output.push([fullwordsData[i], partialsData[ii].value]);
        partialsData.splice(ii, 1);
        break;
      }
    }
  }
  if(partialsData.length > 0){
    var missedData = GenerateMissedPartialsArray(partialsData);
    output = output.concat(missedData);
  }  
  return output;
}

//Generates a missed partials array based on the partials that found no match.
function GenerateMissedPartialsArray(partialsData){
  var output = [];
  for(var  i = 0; i < partialsData.length; i++){
    output.push(['No Match', partialsData[i].value])
  }
  return output;
}

//Generates the regex array for the partials
function GeneratePartialsRegexArray(partialsArray){
  var output = [];
  for(var  i = 0; i < partialsArray.length; i++){
    output.push({regex: new RegExp(partialsArray[i], 'i'), value: partialsArray[i]});
  }
  return output;
}

//http://stackoverflow.com/a/13305008/3547347
function SortByKeys(itemsArray, sortingArray){
  var itemsMap = CreateItemsMap(itemsArray), result = [];
  for (var i = 0; i < sortingArray.length; ++i) {
    var key = sortingArray[i];
    result.push([itemsMap[key].shift()]);
  }
  return result;  
}

//http://stackoverflow.com/a/13305008/3547347
function CreateItemsMap(itemsArray) {
  var itemsMap = {};
  for (var i = 0, item; (item = itemsArray[i]); ++i) {
    (itemsMap[item[1]] || (itemsMap[item[1]] = [])).push(item[0]);
  }
  return itemsMap;
}

//Gets a column of data as an array
function GetColumnAsArray(valuesRange, columnIndex, ignoreBlank, startRowIndex){
  var output = [];
  for(var  i = startRowIndex; i < valuesRange.length; i++){
    if(ignoreBlank){
      if(valuesRange[i][columnIndex] !== ''){
        output.push(valuesRange[i][columnIndex]);        
      }
      continue;
    }
    output.push(valuesRange[i][columnIndex]);
  }
  return output;
}

//Gets a columns object for the sheet for easy indexing
function GetColumns(valuesRange, columnCount, rowIndex)
{
  var columns = {
    columns: {},
    length: 0
  }

  Logger.log("Populating columns...");
  for(var i = 0; i < columnCount; i++)
  {
    if(valuesRange[0][i] !== ''){
      columns.columns[valuesRange[0][i]] = {index: i ,value: valuesRange[0][i]};
      columns.length++;      
    }
  }  
  return columns;
}

关于某些决定的说明:为了提高性能,我选择不使用map或其他更简洁的数组函数。

答案 1 :(得分:0)

MATCH和LOOKUP不适用于部分匹配。

另一种方法是将SEARCH或FIND与数组公式中的其他函数一起使用。

示例:

  • A列包含长字符串列表
  • Cell B1包含一个短字符串
  • 单元格C1包含一个公式,该公式返回包含B1
  • 中的短字符串的列a中的第一个长字符串
=ArrayFormula(INDEX(A1:A,SORT(IF(search(B1,A1:A),ROW(A1:A),),1,TRUE)))

数据

+---+--------------+-------+-------------+
|   |      A       |   B   |      C      |
+---+--------------+-------+-------------+
| 1 | Orange juice | apple | Apple cider |
| 2 | Apple cider  |       |             |
| 3 | Apple pay    |       |             |
+---+--------------+-------+-------------+

答案 2 :(得分:0)

好的,我想我已经找到了答案。我会在这里发布,以防其他人使用它。

为了给予应有的信用,found it here

这就是我想要的:

=INDEX($D$1:$D$3,MATCH(1,COUNTIF(A1,"*"&$D$1:$D$3&"*"),0))

它确实减慢了一切,因为一切都像疯了一样交叉引用(我的电子表格上有3000行)但是如果在D1-3中有一个单词列表,它将看到单元格A1是否包含一个这些单词并打印出与之匹配的单词。

感谢所有提供解决方案的人,特别是@ douglasg14b - 如果有一个在内存方面不那么重要的话,那就太棒了,但这样做的方式很慢!

由于

塔迪

答案 3 :(得分:0)

这也有效:

=QUERY(FILTER($D$1:$D$3,REGEXMATCH(A1,"(?i)"&$D$1:$D$3)),"limit 1")

我们使用REGEXMATCH(?i)使搜索不区分大小写。查询中的limit 1仅提供第一次出现。