【问题标题】:Multiple regex matches in Google Sheets formulaGoogle表格公式中的多个正则表达式匹配
【发布时间】:2017-09-11 22:41:34
【问题描述】:

我正在尝试使用 Google 表格正则表达式公式获取给定字符串中连字符之前的所有数字的列表(假设在单元格 A1 中):

=REGEXEXTRACT(A1, "\d-")

我的问题是它只返回第一个匹配项...我怎样才能获得所有匹配项

示例文本:

"A1-Nutrition;A2-ActPhysiq;A2-BioMeta;A2-Patho-jour;A2-StgMrktg2;H2-Bioth2/EtudeCas;H2-Bioth2/Gemmo;H2-Bioth2/Oligo;H2-Bioth2/Opo;H2-Bioth2/Organo;H3-Endocrino;H3-Génétiq"

我的公式返回1-,而我想得到1-2-2-2-2-2-2-2-2-2-3-3-(作为数组或连接文本)。

我知道我可以使用脚本或其他函数(如 SPLIT)来实现所需的结果,但我真正想知道的是如何获得 re2 正则表达式以在 "@ 987654328@" 谷歌表格公式。 类似于regex101.com

上的“global - 第一场比赛后不返回”选项

我还尝试使用 REGEXREPLACE 删除不需要的文本,但也没有成功(我无法删除没有连字符前的其他数字)。

任何帮助表示赞赏! 谢谢:)

【问题讨论】:

  • 我认为你很幸运。文档说只返回第一个......
  • @dawg 谢谢,我同意,但我认为必须有一种方法来定义正确的正则表达式以获得所有匹配项;例如,如果我使用((\d-)),我得到前两个匹配项,(((\d-))) 我得到前三个匹配项,但是如何获得所有匹配项,不知道有多少?也许使用组名\1,允许任何由.* 分隔的匹配重复......或者至少通过组合多个REGEXEXTRACT 和/或REGEXREPLACE 公式。
  • 我尝试使用(?g),它适用于一些re口味,但恐怕不适用于re2。这是一个很好的问题。
  • 我喜欢使用捕获组的两个答案。更简单的是, =regexreplace(A1,"(\d-)|.","$1") 似乎可以工作。
  • 是的,我认为=regexreplace(A1,"(\d-)|.","$1") 是迄今为止最好的,谢谢!简单高效:)

标签: regex google-sheets re2


【解决方案1】:

编辑

我想出了更通用的解决方案:

=regexreplace(A1,"(.)?(\d-)|(.)","$2")

它将除第二组匹配 (\d-) 之外的任何文本替换为仅第二组 $2

"(.)?(\d-)|(.)"
  1    2    3  
  Groups are in ()
  ---------------------------------------
 "$2" -- means return the group number 2

学习正则表达式:https://regexone.com


试试这个公式:

=regexreplace(regexreplace(A1,"[^\-0-9]",""),"(\d-)|(.)","$1")

它将像这样处理字符串:

"A1-Nutrition;A2-ActPhysiq;A2-BioM---eta;A2-PH3-Généti***566*9q"

带输出:

1-2-2-2-3-

【讨论】:

  • 有人能解释一下这个公式吗?
  • @Fabian 我添加了一个简短的描述。要深入学习它,我建议使用正则表达式来学习。
  • 谢谢@Max Makhrov!
  • 为什么要捕获第 1 组和第 3 组?更短:=regexreplace(A1,".?(\d-)|.", "$1")
【解决方案2】:

您可以在脚本编辑器中创建自己的自定义函数:

function ExtractAllRegex(input, pattern,groupId) {
  return Array.from(input.matchAll(new RegExp(pattern,'g')), x=>x[groupId]);
}

或者,如果您需要返回单个单元格中的所有匹配项,并用一些分隔符连接:

function ExtractAllRegex(input, pattern,groupId,separator) {
  return Array.from(input.matchAll(new RegExp(pattern,'g')), x=>x[groupId]).join(separator);
}

那么,就叫它=ExtractAllRegex(A1, "\d-", 0, ", ")吧。

说明

  • input - 当前单元格值
  • pattern - 正则表达式模式
  • groupId - 正在捕获要提取的组 ID
  • separator - 用于加入匹配结果的文本。

【讨论】:

  • 感谢您的努力和明确的答案,尽管我在 OP 中写道我不是在寻找基于脚本的解决方案。
  • @flo5783 您写了“我知道我可以使用脚本”,但您没有提供此脚本。这是为了向那些想要遵循这个解决方案的人展示这个替代方案。由于REGEXEXTRACT 不支持多重匹配,所有那些基于REGEXREPLACE 的解决方案都是变通方法,每次都需要调整以适应每种情况。这个小功能是一个通用解决方案,可以弥补缺失的功能。
  • 谢谢你,做到了。即使 OP 不想要脚本,这似乎是其他人偶然发现该问题的唯一“真正”解决方案。
  • @WiktorStribiżew 在尝试将您的函数添加到脚本编辑器时,我收到以下错误:TypeError: Cannot read property 'matchAll' of undefined (line 2, file "Code")Dismiss 您认为如何解决这个问题?谢谢!
  • 再次感谢@WiktorStribiżew,但现在我收到了SyntaxError: Unexpected token ')' (line 4, file "Code.gs")
【解决方案3】:

我无法获得适用于我的案例的公认答案。我想这样做,但需要一个快速的解决方案并采用以下方法:

输入:

1111 days, 123 hours 1234 minutes and 121 seconds

预期输出:

1111 123 1234 121

公式:

=split(REGEXREPLACE(C26,"[a-z,]"," ")," ")

【讨论】:

  • 不同的问题,不同的解决方案。你的情况更简单。就我而言,我还有其他数字在没有连字符之前被忽略。
【解决方案4】:

您实际上可以在单个公式中使用 regexreplace 来使用捕获组包围所有值,而不是替换文本:

=join("",REGEXEXTRACT(A1,REGEXREPLACE(A1,"(\d-)","($1)")))

基本上它所做的是将\d- 的所有实例用一个“捕获组”包围,然后使用正则表达式提取,它巧妙地返回所有捕获。如果你想将它重新加入一个字符串,你可以使用 join 将它重新打包成一个单元格:

【讨论】:

  • 无法让它工作。 regexextract 的第二段需要一个字符串,而 regexreplace 的输出与 A1 不匹配。
  • Pacerier 的输入是什么
  • 这太棒了。 @Pacerier 这里有一个提示:在一个单元格中单独执行 RegexReplace。确保输出完全是原始字符串,除了您需要捕获的项目周围的括号()。一旦这是真的,然后将结果放入 Aurielle 提到的 RegexReplace 中。
  • 顺便说一句,如果这不起作用,那么这可能意味着您的字符串有一些额外的字符会混淆正则表达式函数,例如“[”、“(”、“?”、“+”等。尝试先把它们去掉!
【解决方案5】:

这似乎有效,我已尝试验证它。

逻辑是

(1) 将后跟连字符的字母替换为空

(2) 将任何不带连字符的数字替换为空

(3) 将不是数字或连字符的所有内容替换为空

=regexreplace(A1,"[a-zA-Z]-|[0-9][^-]|[a-zA-Z;/é]","")

结果

1-2-2-2-2-2-2-2-2-2-3-3-

分析

我必须在程序上逐步完成这些以说服自己这是正确的。根据this reference,当存在由管道符号分隔的替代方案时,正则表达式应按从左到右的顺序匹配它们。除非规则 1 首先出现,否则上述公式无法正常工作(否则它会在规则 (1) 生效之前将除数字或连字符之外的所有字符减少为空,并且您会从“Patho-jour”中获得一个额外的连字符)。

以下是我认为它必须如何处理文本的一些示例

【讨论】:

  • 谢谢,我仍然希望有一个更优雅或更通用的解决方案来适应 re2 中的所有匹配项,但这对我来说确实有用,我非常感谢详细的解释和研究!跨度>
  • 谢谢,非常感谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-10-08
  • 1970-01-01
  • 2012-11-21
相关资源
最近更新 更多