Google 从列表中多次搜索和替换工作表

Google Sheets multiple search and replace from a list

我正在寻找一种解决方案,用于在 Google Sheet 中搜索某些字符串,找到后,将它们替换为另一个 sheet 中列表中的另一个字符串。

为了更好的理解,我为大家准备了一个Sheet:

https://docs.google.com/a/vicampo.de/spreadsheets/d/1mETtAY72K6ST-hg1qOU9651265nGq0qvcgvzMRqHDO8/edit?usp=sharing

所以这是我想要完成的确切任务:

在 sheet "Text" 的 A 列的每个单元格中,查找 sheet "List" 的 A 列中给出的字符串,并且,找到后,将其替换为 sheet "List".

的 B 列中的相应字符串

参见我的示例:在单元格 A1 中查找字符串 "Lorem" 并将其替换为 "Xlorem",然后查找字符串 "Ipsum" 并将其替换为 "Xipsum" ,然后查找字符串 "amet" 并将其替换为 "Xamet" 然后转到单元格 B1 并再次开始查找字符串...

我尝试了不同的功能,并设法用一个单元格的功能来做到这一点。但是怎么循环呢?

感谢所有有兴趣帮助解决这个问题的人

虽然必须有'nicer'个解决方案,但一个快速的解决方案(只要你要替换的单词的单元格数量不太长)是:

=ArrayFormula(regexreplace(regexreplace(regexreplace(A1:A; List!A1; List!B1); List!A2; List!B2); List!A3; List!B3))

Copy Sample File With Explanation

问题

挑战是: 在多个单元格的输入中查找并替换多个值。

ArrayFormula 的

我算作Array-Solution的解必须是:

  1. 基于开区间
  2. 无需拖拽公式
  3. 列表中出现新项目时无需修改公式

必须通过这些测试:

  • ArrayFormula
  • 用户可以设置区分大小写
  • 替换表情符号
  • 替换特殊字符 $\[].
  • 碰撞测试。适用于 10K 行数据
  • 碰撞测试。适用于 2K 替换

脚本

在这种情况下,我建议使用不基于正则表达式的脚本。该算法通过字符查找和替换文本:

用法

用作来自 sheet 的常规公式:

=substitutes(A12:A;List!A1:B)

代码

保存此代码以使用上面的公式:

/**
 * Substitutes in every entry in array
 * Text from prefilled array
 *
 * @param {array} input The array of strings.
 * @param {array} subTable The array of string pairs: search texts / replace texts.
 * @param {boolean} caseSensitive [optional=false] 
 * TRUE to match Apple and apple as different words
 * @return The input with all replacement made
 * @customfunction
 */
function substitutes(input, subTable,caseSensitive) {
  //  default behavior it is not case sensitive
  caseSensitive = caseSensitive || false;
  // if the input is not a list, become a list */
  if( typeof input != "object" ) {
    input = [ input ];
  }
  var res = [], text;
  for (var i = 0; i < input.length; i++) {
    // force each array element in the input be a string
    text = input[i].toString();
    for (var ii = 0; ii < subTable.length; ii++) {
      text = replaceAll_(
        text, 
        subTable[ii][0], 
        subTable[ii][1], 
        caseSensitive);
    }
    res.push(text);
  }
  return res;
}


/***
 * JavaScript Non-regex Replace
 * 
 * Original code sourse:
 * 
 */
function replaceAll_(str, find, newToken, caseSensitive) {
    var i = -1;
    // sanity check & defaults
    if (!str) {
        // Instead of throwing, act as 
        // COALESCE if find == null/empty and str == null
        if ((str == null) && (find == null))
            return newToken;
        return str;
    }
    if (!find || find === ''){ return str; }
    if (find === newToken) { return str; }
    caseSensitive = caseSensitive || false;
    find = !caseSensitive ? find.toLowerCase() : find;
    // search process, search by char
    while ((
        i = (!caseSensitive ? str.toLowerCase() : str).indexOf(
            find, i >= 0 ? i + newToken.length : 0
        )) !== -1
    ) {
        str = str.substring(0, i) +
            newToken +
            str.substring(i + find.length);
    } 
    return str;
}

怪物公式

我用RegEx算法用原生函数解决了。不推荐使用此方法,因为它会减慢您的工作速度sheet.

公式为:

=INDEX(SUBSTITUTE(REGEXREPLACE(TRANSPOSE(QUERY(TRANSPOSE(IFERROR(SPLIT(SUBSTITUTE(TRANSPOSE(QUERY(TRANSPOSE(IFERROR(VLOOKUP(SPLIT(REGEXREPLACE(A12:A;SUBSTITUTE(REGEXREPLACE(REGEXREPLACE(A12:A;"(?i)"&SUBSTITUTE(SUBSTITUTE(QUERY(FILTER(REGEXREPLACE(List!A1:A;"(\|\+|\*|\?|\[|\^|\]|$|\(|\)|\{|\}|\=|\!|\<|\>|\||\:|\-)";"\")&"";List!A1:A<>"");;2^99);" ";"|");"";"");"");"(\|\+|\*|\?|\[|\^|\]|$|\(|\)|\{|\}|\=|\!|\<|\>|\||\:|\-)";"\");"";"(.*)");INDEX(REGEXREPLACE(TRIM(TRANSPOSE(QUERY(TRANSPOSE(IF(SEQUENCE(COUNTA(INDEX(LEN(REGEXREPLACE(REGEXREPLACE(A12:A;"(?i)"&SUBSTITUTE(SUBSTITUTE(QUERY(FILTER(REGEXREPLACE(List!A1:A;"(\|\+|\*|\?|\[|\^|\]|$|\(|\)|\{|\}|\=|\!|\<|\>|\||\:|\-)";"\")&"";List!A1:A<>"");;2^99);" ";"|");"";"");"");"[^]";""))/2));MAX(INDEX(LEN(REGEXREPLACE(REGEXREPLACE(A12:A;"(?i)"&SUBSTITUTE(SUBSTITUTE(QUERY(FILTER(REGEXREPLACE(List!A1:A;"(\|\+|\*|\?|\[|\^|\]|$|\(|\)|\{|\}|\=|\!|\<|\>|\||\:|\-)";"\")&"";List!A1:A<>"");;2^99);" ";"|");"";"");"");"[^]";""))/2)))-(SEQUENCE(COUNTA(INDEX(LEN(REGEXREPLACE(REGEXREPLACE(A12:A;"(?i)"&SUBSTITUTE(SUBSTITUTE(QUERY(FILTER(REGEXREPLACE(List!A1:A;"(\|\+|\*|\?|\[|\^|\]|$|\(|\)|\{|\}|\=|\!|\<|\>|\||\:|\-)";"\")&"";List!A1:A<>"");;2^99);" ";"|");"";"");"");"[^]";""))/2)))-1)*MAX(INDEX(LEN(REGEXREPLACE(REGEXREPLACE(A12:A;"(?i)"&SUBSTITUTE(SUBSTITUTE(QUERY(FILTER(REGEXREPLACE(List!A1:A;"(\|\+|\*|\?|\[|\^|\]|$|\(|\)|\{|\}|\=|\!|\<|\>|\||\:|\-)";"\")&"";List!A1:A<>"");;2^99);" ";"|");"";"");"");"[^]";""))/2))<=INDEX(LEN(REGEXREPLACE(REGEXREPLACE(A12:A;"(?i)"&SUBSTITUTE(SUBSTITUTE(QUERY(FILTER(REGEXREPLACE(List!A1:A;"(\|\+|\*|\?|\[|\^|\]|$|\(|\)|\{|\}|\=|\!|\<|\>|\||\:|\-)";"\")&"";List!A1:A<>"");;2^99);" ";"|");"";"");"");"[^]";""))/2);""&SEQUENCE(COUNTA(INDEX(LEN(REGEXREPLACE(REGEXREPLACE(A12:A;"(?i)"&SUBSTITUTE(SUBSTITUTE(QUERY(FILTER(REGEXREPLACE(List!A1:A;"(\|\+|\*|\?|\[|\^|\]|$|\(|\)|\{|\}|\=|\!|\<|\>|\||\:|\-)";"\")&"";List!A1:A<>"");;2^99);" ";"|");"";"");"");"[^]";""))/2));MAX(INDEX(LEN(REGEXREPLACE(REGEXREPLACE(A12:A;"(?i)"&SUBSTITUTE(SUBSTITUTE(QUERY(FILTER(REGEXREPLACE(List!A1:A;"(\|\+|\*|\?|\[|\^|\]|$|\(|\)|\{|\}|\=|\!|\<|\>|\||\:|\-)";"\")&"";List!A1:A<>"");;2^99);" ";"|");"";"");"");"[^]";""))/2)))-(SEQUENCE(COUNTA(INDEX(LEN(REGEXREPLACE(REGEXREPLACE(A12:A;"(?i)"&SUBSTITUTE(SUBSTITUTE(QUERY(FILTER(REGEXREPLACE(List!A1:A;"(\|\+|\*|\?|\[|\^|\]|$|\(|\)|\{|\}|\=|\!|\<|\>|\||\:|\-)";"\")&"";List!A1:A<>"");;2^99);" ";"|");"";"");"");"[^]";""))/2)))-1)*MAX(INDEX(LEN(REGEXREPLACE(REGEXREPLACE(A12:A;"(?i)"&SUBSTITUTE(SUBSTITUTE(QUERY(FILTER(REGEXREPLACE(List!A1:A;"(\|\+|\*|\?|\[|\^|\]|$|\(|\)|\{|\}|\=|\!|\<|\>|\||\:|\-)";"\")&"";List!A1:A<>"");;2^99);" ";"|");"";"");"");"[^]";""))/2))&"";));;2^99)));" ?";"$")));"");{List!A1:A\List!B1:B};2;)&""));;2^99));" ";"")&"";"")&SPLIT(REGEXREPLACE(A12:A;"(?i)"&SUBSTITUTE(SUBSTITUTE(QUERY(FILTER(REGEXREPLACE(List!A1:A;"(\|\+|\*|\?|\[|\^|\]|$|\(|\)|\{|\}|\=|\!|\<|\>|\||\:|\-)";"\")&"";List!A1:A<>"");;2^99);" ";"|");"";"");"")&"";"")))&"";;2^99));" *";"");"";""))

其他解决方案

嵌套公式

其他答案中提到的嵌套 SUBSTITUTEREGEXREPLACE 公式。

您需要向下拖动结果的公式

这是一个示例公式。基本逻辑-将文本拆分成部分→单独修改部分→加入新结果。

这个公式必须抄下来:

=JOIN(" ";
ArrayFormula(
IFERROR(VLOOKUP(TRANSPOSE(SPLIT(A1;" "));List!A:B;2;0);TRANSPOSE(SPLIT(A1;" ")))))

在这种情况下,可能最适合您的方法是为您的 Google 电子表格创建一个新函数。在一般情况下,它往往比那些应该做同样事情的复杂公式更简单、清晰和强大。

在这个特殊情况下,我遇到了同样的问题,所以你可以使用相同的功能:

单击“工具”菜单,然后单击“脚本编辑器”选项。进入脚本编辑器,擦除草稿并粘贴此函数:

function preg_quote( str ) {
  // http://kevin.vanzonneveld.net
  // +   original by: booeyOH
  // +   improved by: Ates Goral (http://magnetiq.com)
  // +   improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
  // +   bugfixed by: Onno Marsman
  // *     example 1: preg_quote("");
  // *     returns 1: '$40'
  // *     example 2: preg_quote("*RRRING* Hello?");
  // *     returns 2: '\*RRRING\* Hello\?'
  // *     example 3: preg_quote("\.+*?[^]$(){}=!<>|:");
  // *     returns 3: '\\.\+\*\?\[\^\]$\(\)\{\}\=\!\<\>\|\:'

  return (str+'').replace(/([\\.\+\*\?\[\^\]$\(\)\{\}\=\!\<\>\|\:])/g, "\");
}

function ARRAYREPLACE(input,fromList,toList,caseSensitive){
  /* default behavior it is not case sensitive */
  if( caseSensitive === undefined ){
    caseSensitive = false;
  }
  /* if the from list it is not a list, become a list */
  if( typeof fromList != "object" ) {
    fromList = [ fromList ];
  }
  /* if the to list it is not a list, become a list */
  if( typeof toList != "object" ) {
    toList = [ toList ];
  }
  /* force the input be a string */
  var result = input.toString();

  /* iterates using the max size */
  var bigger  = Math.max( fromList.length, toList.length) ;

  /* defines the words separators */
  var arrWordSeparator = [ ".", ",", ";", " " ];

  /* interate into the lists */
  for(var i = 0; i < bigger; i++ ) {
    /* get the word that should be replaced */
    var fromValue = fromList[ ( i % ( fromList.length ) ) ]
    /* get the new word that should replace */
    var toValue = toList[ ( i % ( toList.length ) ) ]

    /* do not replace undefined */
    if ( fromValue === undefined ) {
      continue;
    }
    if ( toValue == undefined ) {
      toValue = "";
    }

    /* apply case sensitive rule */
    var caseRule = "g";
    if( !caseSensitive ) {
      /* make the regex case insensitive */
      caseRule = "gi";
    }

    /* for each end word char, make the replacement and update the result */
    for ( var j = 0; j < arrWordSeparator.length; j++ ) {
      
      /* from value being the first word of the string */
      result =  result.replace( new RegExp( "^(" + preg_quote( fromValue + arrWordSeparator[ j ] ) + ")" , caseRule ), toValue + arrWordSeparator[ j ] );
      
      /* from value being the last word of the string */
      result =  result.replace( new RegExp( "(" + preg_quote( arrWordSeparator[ j ] + fromValue ) + ")$" , caseRule ), arrWordSeparator[ j ] + toValue );
      
      /* from value in the middle of the string between two word separators */
      for ( var k = 0; k < arrWordSeparator.length; k++ ) {
        result =  result.replace( 
          new RegExp( 
            "(" + preg_quote( arrWordSeparator[ j ] + fromValue + arrWordSeparator[ k ] ) + ")" , 
            caseRule 
          ), 
          /* need to keep the same word separators */
          arrWordSeparator[ j ] + toValue + arrWordSeparator[ k ] 
        );
      }
    }
    
    /* from value it is the only thing in the string */
    result =  result.replace( new RegExp( "^(" + preg_quote( fromValue ) + ")$" , caseRule ), toValue );
  }
  /* return the new result */
  return result;
}

只需保存您的脚本,您就可以使用它的新功能。现在,您有了用第二个值列表替换所有第一个值列表的函数。

=ARRAYREPLACE(C2;A1:A4;B1:B4)

例如,获取 C2 文本并将 A1:A4 列表中找到的所有元素替换为 B1:B4 列表中的等效元素。

对 JPV 答案的改进,速度提高了几个数量级,并适用于任意查询和替换字符串:

=ArrayFormula(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(A1:A, List!A1, List!B1), List!A2, List!B2), List!A3, List!B3))

使用这种格式,一个包含 15,000 个单元格和一个 85 长的替换列表的电子表格将在几秒钟内更新。只需 assemble 使用您选择的脚本语言的公式字符串就可以了!

这里的脚本比 Thiago Mata 的脚本简单一些。我修改了 https://webapps.stackexchange.com/a/46895 的脚本以支持单个单元格或范围输入

function MSUBSTITUTE(input, subTable)
{
  var searchArray = [], subArray = [], outputArray = [];
  for (var i = 0, length = subTable.length; i < length; i++)
  {
    if (subTable[i][0])
    {
      searchArray.push(subTable[i][0]);
      subArray.push(subTable[i][1]);
    }
  }
  var re = new RegExp(searchArray.join('|'), 'g');
  
  /* Check if we got just a single string */
  if (typeof( input ) == "string")
  {
    outputArray.push(input.replace(re, function (match) {return subArray[searchArray.indexOf(match)];}));
  } 
  else /* we got an array of strings */
  {
    for (var i = 0; i < input.length; i++)
    {
      /* force each array element in the input be a string */
      var text = input[i].toString();
      outputArray.push(text.replace(re, function (match) {return subArray[searchArray.indexOf(match)];}))
    }
  }
  return outputArray;
}

知道了

Lorem ipsum dolor sit xamet Lorem ipsum

= textjoin("";true;ARRAYFORMULA(ifna(vlookup(REGEXEXTRACT(A1;"("&REGEXREPLACE(A1;"("&(textJOIN("|";true;lookuprange))&")";")()(")&")");lookuprange;2;false);REGEXEXTRACT(A1;"("&REGEXREPLACE(A1;"("&(textJOIN("|";true;lookuprange))&")";")()(")&")"))))

Xlorem ipsum dolor sit Xamet Xlorem ipsum

我找到了使用“ARRAYFORMULA”执行此操作的简单方法

您必须有一个包含要查找的文本的列表,并且在连续的列中,要替换数据的列表,例如:

# D E
1 ToFind ToReplace
2 Avoc4do Avocado
3 Tomat3 Tomate
4 On1on Onion
5 Sug4r Sugar

然后使用这个公式

=数组公式(查找(A1:A1000,D1:D5,E1:E5))

A​​1:A1000 是原始列,其中有多行包含单词“Avoc4do、Tomat3、On1on、Sugar”,ArrayFormula 使用其他公式无法使用的矩阵(公式 FIND 无法在一个矩阵,所以我们使用 ArrayFormula) 然后你将有一个包含 1000 行的列,但现在按顺序排列了“ToReplace”文本,所以现在在 A 列中剪切并复制,就是这样。