【问题标题】:Extract TextString between second and third hyphen在第二个和第三个连字符之间提取 TextString
【发布时间】:2020-05-03 15:41:23
【问题描述】:

我正在尝试使用 RegEx 从我的一个列中的字符串中提取一些信息。

我需要定义第二列,等于第一列中第 2 次和第 3 次出现连字符之间的值。

经过多次谷歌搜索,我设法做到了这一点:

IFNULL(SAFE.REGEXP_EXTRACT(Final.CampaignName, r"(?:\w+\s+-\s+){2}(\w+)\s+-"), "Other") AS CampaignCategory

Final.CampaignName 中的字符串的外观示例:

S - 橙子 - 酒吧 - 苹果

S - 苹果 - Foo Bar - 橙子 - 香蕉

S - 苹果 - 酒吧

如果第二个和第三个连字符之间有 1 个单词,我的正则表达式只会返回该值,但我需要返回整个文本(减去前导和尾随空格)。

谁能指导我做这件事的正确方向?

谢谢!

【问题讨论】:

  • 请编辑以阐明每个示例要返回的内容。前两个很明显。对于第三个,第二个和第三个连字符之间没有文本(因为没有第三个连字符),那么要返回什么?一个空字符串?一个错误?如果您想返回Bar,您需要修改问题的措辞。不同的答案对此做出了不同的假设。
  • 基于上下文 - 我强烈认为第三个示例的输出应该是 Bar。显然这是假设上下文被正确表示。
  • 我很抱歉。我确实希望第三个示例也能返回Bar。谢谢你们两个的回答。 Cary 帮助我更好地理解 RegEx,而 Mikhail 为我的 BQ 示例提供了完美的答案 :)

标签: regex google-bigquery


【解决方案1】:

我快到了 - 所以,下面的内容尽可能接近您的原始想法(BigQuery 标准 SQL)

SELECT IFNULL(REGEXP_EXTRACT(final.CampaignName, r"(?: - .*?){2}(.*?)(?: -|$)"), "Other") AS CampaignCategory

【讨论】:

    【解决方案2】:

    使用以下模式和捕获组来隔离您真正想要提取的内容:

    SAFE.REGEXP_EXTRACT(Final.CampaignName, r"[^-]+-[^-]+-\s*([^-]+?)\s*-") AS CampaignCategory
    

    Demo

    【讨论】:

      【解决方案3】:

      您可以使用捕获组匹配第二个和第三个连字符之间的内容,并使用带有* 的重复模式将其余部分匹配为可选

      \w+(?:\s+-\s+\w+)\s+-\s+(\w+(?: \w+)*)(?:\s+-\s+\w+)*
      

      Regex demo

      【讨论】:

        【解决方案4】:

        如果正则表达式引擎支持\K(松散地,忘记到目前为止匹配的所有内容),可以使用以下正则表达式来匹配第二个和第三个连字符之间的文本。

        ^(?:[^-]+-){2}\K[^-]+(?=-)
        

        请注意,此正则表达式不包含捕获组。

        Demo

        这与第三个示例中的 Bar 不匹配,因为只有两个连字符。要匹配 Bar,只需删除前瞻 (?=-)

        正则表达式引擎执行以下操作。

        ^           match beginning of line
        (?:[^-]+-)  match 1+ chars other than '-' followed by '-'
                    in a non-capture group
        {2}         execute non-capture group twice
        \K          discard everything matched so far (reset the starting
                    point of the reported match)
        [^-]+       match 1+ chars other than '-'
        (?=-)       match '-' in a positive lookahead
        

        如果[^-] 不匹配换行符,请将其更改为[^-\r\n]

        如果不支持\K,则需要捕获组(并且不需要前瞻):

        ^(?:[^-]+-){2}([^-]+)-
        

        【讨论】:

        • 感谢您的解决方案和详尽的解释,Cary!
        • REGEXP_EXTRACT 支持捕获组,因此不需要您的第一种方法。
        • @Tim,我认为是这样,但由于包括您自己在内的其他人提供了使用捕获组的解决方案,我想我会提出一些不同的建议,主要是出于教育原因。
        【解决方案5】:

        如果可能,我总是更喜欢其他方式,而不是使用正则表达式。 因此,对于您的问题,我可以推荐该代码:

        split(Final.CampaignName, ' - ')[safe_offset(2)]
        

        您的示例数据示例:

        select campaignName, split(campaignName, ' - ')[safe_offset(2)] as third_item
        from unnest(['S - Oranges - Bar - Apples', 'S - Apples - Foo Bar - Oranges - Bananas', 'S - Apples - Bar']) as campaignName
        

        输出如下所示:

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2020-04-27
          • 2021-10-15
          • 1970-01-01
          • 2018-03-17
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多