【问题标题】:Attempting to split all 4 digit numbers in spreadsheet cells with regex and formulas尝试使用正则表达式和公式拆分电子表格单元格中的所有 4 位数字
【发布时间】:2018-01-10 05:43:19
【问题描述】:

我目前在使用 Google 电子表格中的拆分和正则表达式时遇到了一些困难。我试图将单元格的内容分成一行,但只提取四个连续数字的序列(代表年份)并且只使用单元格公式(而不是函数)。最终,这个公式将适用于整个列,但我暂时将其限制为单个单元格。例如,给定一个包含内容的单元格“I2”:

2009;国会图书馆; 1939-1945; 1984 年第 23 次; 16

我需要一个结果(放在“J2、K2、L2、M2 等”中),例如:

2009 1939 1945 1984

尽管分号之间的条目数量从一个到多个不等,但这个示例单元格在我所知道的可能出现的各种可能性中具有代表性。到目前为止,在我自己的尝试中,我最终得到了两个接近我需要的公式,但都达不到要求。

1) 第一个公式为:

=ArrayFormula(SPLIT(SUBSTITUTE(REGEXREPLACE(I$2, "[^\d\-\;]", ""),"-", ";"), ";"))

实现(在“J2,K2,L2,M2,N2”中):

2009 1939 1945 231984 16

2) 第二个公式是:

=ArrayFormula(SPLIT(SUBSTITUTE(REGEXREPLACE(REGEXREPLACE(I$2, "[^\d]", ";"), "[^\d\-\;]", ""),"-", ";"), ";"))

这让我(在“J2、K2、L2、M2、N2、O2”中):

2009 1939 1945 23 1984 16

我一直在想办法用“\d{4}”来限制公式的返回,但到目前为止我所做的组合或更改都没有成功。有没有人有任何见解可以解决这个问题?

【问题讨论】:

  • 谷歌正则表达式有单词边界标记吗?如果是这样,则使用模式\b\d{4}\b
  • 到目前为止,我还没有遇到任何关于 Google 使用单词边界标记的能力的参考,不;我认为那也可以。我只是尝试再次用您的建议替换某些部分,但它返回了错误。根据上述公式,您想到了对 "\b\d{4}\b" 的哪些特殊更改?
  • 在 Excel 中,数组公式可以返回值数组。所以我会认为在Sheets 中,ArrayFormula(REGEXEXTRACT(your_string,"\b\d{4}\b")) 之类的东西会返回一个包含所有四位数匹配的数组。但是,我不熟悉Sheets,除了第一场比赛外,我无法让它返回。哦,\b 令牌在Sheets 使用的RE 文档中列为可用。所以问题似乎是返回所有匹配项,而不仅仅是第一个匹配项。
  • 找到了一种使用 REGEXEXTRACT 返回所有匹配项的方法。与 Excel 相比,它似乎很麻烦,但请参阅下面的答案。

标签: regex split google-sheets formulas


【解决方案1】:

以下似乎可行,虽然我不是表格专家,但可能有更有效的方法。

显然,如果您使用捕获组,REGEXEXTRACT 将返回一个值数组。但是,此方法似乎要求您知道要提取的匹配项的确切数量。

所以以下似乎有效:

=REGEXEXTRACT($I2,REPT("(\b\d{4}\b).*?",(len($I2)-len(REGEXREPLACE($I2,"\b\d{4}\b","")))/4))

它是如何工作的:

首先计算字符串中的匹配数:

=(len(I2)-len(REGEXREPLACE(I2,"\b\d{4}\b","")))/4

接下来,创建一个包含正则表达式正确次数的正则表达式:

REPT("(\b\d{4}\b).*?", ...Above_formula...)

最后,我们将它们放在上面的最终公式中。

当然,如果您知道匹配数始终为四 (4),则无需以这种方式构造正则表达式字符串,您只需对其进行硬编码即可。

编辑要在没有匹配项的情况下消除不需要的零,请使用REGEXMATCH 测试是否有任何匹配项:例如:

=ArrayFormula(if(REGEXMATCH($I2,"\b\d{4}\b"),(value(REGEXEXTRACT($I2,REPT("(\b\d{4}\b).*?",(len($I2)-len(REGEXREPLACE($I2,"\b\d{4}\b","")))/4)))),""))

【讨论】:

  • 这似乎也很好用,是的;谢谢!结果的唯一问题是返回的值注册为“False”,(例如)=ISNUMBER(J2)。我还在对返回的数组进行四分位数分析,所以这是非常必要的。有没有办法将结果转换为数字格式,以便它们注册为“真”?我尝试将 VALUE 添加到公式中,但这样做会将结果减少到第一个数字(2009 年)。
  • @A.K.只需将其作为数组公式输入(使用 VALUE 函数),它就会返回一个数字数组。
  • 效果很好,罗恩;谢谢!这里出现的最后一个问题是,尽管所有行都按应有的方式显示日期,但如果没有任何内容符合条件,它们也会用“0”填充所有剩余的列。这一直持续到已填充日期的最远列,因此它最终看起来像一个表,其中的 0 比任何东西都多(在这一切上都扔掉了 AVERAGE 函数)。如果没有日期或更多日期,有没有办法在返回空格“”的 IF 语句中成功分层?到目前为止,我的尝试都返回了错误。
  • 嗯?您最初的问题与日期无关,我建议的公式也不应该返回日期。此外,当我从 J2 复制公式时,仅填充具有四位数字的列,因此如果匹配,则仅列 J;如果有两个:J & K 等。
  • 你是对的;我使用 4 位数字来表示日期,但结果是数字格式而不是日期格式(这是我故意的;我的错误是不清楚!)。为了按照您的建议获取数值数组,我将公式更改为: =ArrayFormula(Value(REGEXEXTRACT(I2:I,REPT("(\b\d{4}\b).*?",(len(I2 :I)-len(REGEXREPLACE(I2:I,"\b\d{4}\b","")))/4)))) 这就是让我明白的原因: "2009 1939 1945 1984", " 0 0 0 0”和“2005 1910 0 0”,来自“2009;国会图书馆;1939-1945;1984 年 23 日;16”,“国会图书馆”和“2005;1910”
【解决方案2】:

使用这个公式,也许将冒号作为拆分字符替换为另一个不太可能出现在源字符串中的字符。

=filter(split(regexreplace(I$2, "\D+", ":"), ":"), len(split(regexreplace(I$2, "\D+", ":"), ":"))=4)

说明:这是一种绕过 Google RE2 引擎中正则表达式限制的方法。我们不是寻找模式,而是寻找反模式(任何不是数字的东西)并将其替换为分隔符,然后拆分。剩下的只是由数字组成的子串,所以我们过滤它们,只剩下 4 个字符的子串。

【讨论】:

  • 这简直是完美的;谢谢,塔查拉!我唯一的额外问题是现在如何将公式扩展到整个列,而无需手动将其拖动到给定点。看起来使用 FILTER 会阻止使用 I2:I 和数组公式来自动填充列中的所有单元格,这就是我对前面两个公式所做的。如果我尝试这样做,我会收到错误消息:>“过滤器范围必须是单行或单列。”
  • 恐怕您将不得不为此使用用户定义的函数方法。我希望自己知道如何强制 arrayformula 以我想要的方式循环......
猜你喜欢
  • 2014-02-07
  • 2018-01-12
  • 1970-01-01
  • 1970-01-01
  • 2020-01-14
  • 1970-01-01
  • 1970-01-01
  • 2020-03-06
  • 2015-03-24
相关资源
最近更新 更多