Google 表格:如何根据一列不同的选项从字符串中提取部分文本?

Google Sheets: How can I extract partial text from a string based on a column of different options?

目标: 我有一堆关键词,我想根据我设置的主题参数自动分类。匹配的类别必须在同一列中,以便过滤关键字数据。

例如如果我将“小狗”作为第一个主题,它不应作为第二或第三主题出现,否则无法根据需要过滤数据。

示例数据: https://docs.google.com/spreadsheets/d/1TWYepApOtWDlwoTP8zkaflD7AoxD_LZ4PxssSpFlrWQ/edit?usp=sharing

视频: https://drive.google.com/file/d/11T5hhyestKRY4GpuwC7RF6tx-xQudNok/view?usp=sharing

参数选项卡: 我将在 D-F 列中添加根据关键字数据集而变化的词,对于更大的数据集,通常会有数百个(如果不是数千个)选项.

类别选项卡:我想要一个公式或脚本,它沿着参数中的 D-F 列向下移动并填写相应的值(分别在类别中!分别为 D-F 列)基于与 B 列或 C 列的部分匹配(是否有像 space 这样的定界符对我来说没有区别。最终数据 sheet 应该只有这些列之一)。

我尝试过的事情: 我已经尝试了很多东西。带有正则表达式匹配的嵌套 IF 公式有效但看起来笨拙。

例如这个公式在类别中! D 列

=IF(REGEXMATCH($B2,LOWER(Parameters!$D$3)),Parameters!$D$3,IF(REGEXMATCH($B2,LOWER(Parameters!$D$4)),Parameters!$D $4,""))

我将更多语句嵌套到 Parameters!D 列中的下一个单元格(如在 中,手动添加 $D$5、$D$6 等),但这对于数千个单词长的列表来说似乎效率低下。例如一旦添加了所有犬种类型,第三个主题将变得很长。

有什么建议吗?

我还没搞定的功能: 如果类别 B 或 C 中的字符串在我设置的参数中包含多个主题,有没有办法让前 2 个显示而不是只显示第一个?

例如类别中的 A14 单元格,如何获得 formula/automation 将“Akita”和“German Shepherd”都添加到第三个主题中?与 CHAR(10) 连接以添加到新行是这里的理想格式。将有其他关键字不会同时存在,在这种情况下,这些值将单独显示。

由于这个数据集有一堆混合品种,并且所有品种都被添加为第三个主题,所以区分对混合品种和纯品种的兴趣而不会混淆会很好。

任何想法将不胜感激!此外,如果您有更有创意的解决方案,我愿意接受 spreadsheet 布局和功能的变化。我只关心高效地自动化一项繁琐的任务!!

尝试使用自定义函数:

创建自定义函数:

1.Create 或在 Google 表格中打开电子表格。

2.Select 菜单项工具 > 脚本编辑器。

3.Delete 脚本编辑器中的任意代码,将下面的代码复制并粘贴到脚本编辑器中。

4.At置顶,点击保存保存。

要使用自定义函数:

1.Click 您要使用函数的单元格。

2.Type 等号 (=) 后跟函数名称和任何输入值 — 例如,=DOUBLE(A1) — 然后按 Enter。

3.The 单元格将暂时显示正在加载...,然后 return 结果。

代码:

function matchTopic(p, str) {
  var params = p.flat(); //Convert 2d array into 1d
  var buildRegex = params.map(i => '(' + i + ')').join('|'); //convert array into series of capturing groups. Example (Dog)|(Puppies)
  var regex = new RegExp(buildRegex,"gi");
  var results = str.match(regex);
  if(results){
    // The for loops below will convert the first character of each word to Uppercase
    for(var i = 0 ; i < results.length ; i++){
        var words = results[i].split(" ");
        for (let j = 0; j < words.length; j++) {
          words[j] = words[j][0].toUpperCase() + words[j].substr(1);
        }
        results[i] = words.join(" ");
    }       
    return results.join(","); //return with comma separator
  }else{
    return ""; //return blank if result is null
  }
}

用法示例:

参数:

第一个主题:

第二题:

第三题:

参考:

我为您的每个关键字列添加了一个新的 sheet(“Erik 帮助”),其中包含单独的公式(当前以绿色突出显示)。除了特定的列引用外,它们基本上都是相同的,因此我将在此处仅包含“第一个主题”公式:

=ArrayFormula({"First Topic";IF(A2:A="",,IFERROR(REGEXEXTRACT(LOWER(B2:B&C2:C),JOIN("|",LOWER(FILTER(Parameters!D3:D,Parameters!D3:D<>""))))) & IFERROR(CHAR(10)&REGEXEXTRACT(REGEXREPLACE(LOWER(B2:B&C2:C),IFERROR(REGEXEXTRACT(LOWER(B2:B&C2:C),JOIN("|",LOWER(FILTER(Parameters!D3:D,Parameters!D3:D<>""))))),""),JOIN("|",LOWER(FILTER(Parameters!D3:D,Parameters!D3:D<>""))))))})

此公式首先创建 header(可以根据需要在公式本身内更改)。

打开 IF 条件会使结果列中的任何行留空,前提是该行的 A 列中的相应单元格也为空。

JOIN 用于形成由管道符号分隔的所有关键字的串联字符串,REGEXEXTRACT 解释为 OR.

IFERROR(REGEXEXTRACT(LOWER(B2:B&C2:C),JOIN("|",LOWER(FILTER(Parameters!D3:D,Parameters!D3:D<>""))))) 将尝试从 B 列和 C 列中的每个串联字符串中提取任何关键字。如果找到 none,则 IFERROR 将 return 为空。

然后 second-round 尝试:

& IFERROR(CHAR(10)&REGEXEXTRACT(REGEXREPLACE(LOWER(B2:B&C2:C),IFERROR(REGEXEXTRACT(LOWER(B2:B&C2:C),JOIN("|",LOWER(FILTER(Parameters!D3:D,Parameters!D3:D<>""))))),""),JOIN("|",LOWER(FILTER(Parameters!D3:D,Parameters!D3:D<>"")))))

只是这次用REGEXREPLACE将第一轮的结果替换为null,从而消除了在第二轮中的查找结果。这将导致找到 JOIN 子句中的任何 second 列表(如果存在的话)。否则,IFERROR 再次 return 第二轮无效。

CHAR(10) 是 new-line 字符。

我已经将三个公式中的每一个都写到 return 最多两个结果 每个 关键字列。如果这不是您对“第一个主题”和“第二个主题”的意图(即,如果您只希望每一列最多有一个结果),只需 select 并删除整个 round-two上述公式的一部分来自每一列中的公式。