【问题标题】:How to extract regex query until a specific word?如何提取正则表达式查询直到特定单词?
【发布时间】:2019-07-01 20:19:44
【问题描述】:

我正在尝试从特定标记语言 LookML 中提取某些数据。如果这是示例代码:

explore: explore_name {}
explore: explore_name1 {
  label: "name"
  join: view_name {
      relationship: many_to_one
      type: inner
      sql_on: ${activity_type.activity_name}=${activity_type.activity_name} ;;
  }
}
explore: explore_name3 {}

然后我会收到一个如下所示的列表:

  • explore: character_balance {}
  • label: "name"
    join: activity_type {
      relationship: many_to_one
      type: inner
      sql_on: ${activity_type.activity_name}=${activity_type.activity_name} ;;
    }```
    
  • explore: explore_name4 {}

基本上,我在 "explore" 处开始一场比赛,并在找到另一个 "explore" 时结束比赛——这将开始下一场比赛。

这是我以前的内容,它匹配所有行,直到找到;,这非常好:'explore:\s[^;]*'。但是,假设有一个,这停在一个';'。

我将如何更改它以消除“探索”和“探索”之间的所有内容?只需替换';'在我的 'explore' 正则表达式中,只要找到与 [e,x,p,l,o,r,e] 中的任何内容匹配的字母就会停止 - 这不是我想要的行为。删除方括号和 ^ 最终会破坏所有内容,使其无法跨多行查询。

我应该在这里做什么?

【问题讨论】:

    标签: python regex regex-lookarounds looker


    【解决方案1】:

    一种天真的方法包括到达下一个“探索”词。但是如果出于任何原因,一个字符串值包含这个词,你会得到错误的结果。如果您在字符串包含嵌套括号时尝试停止使用大括号,则会出现同样的问题。

    这就是为什么我建议对您的字符串语法进行更精确的描述,其中考虑到字符串和嵌套的大括号。由于 re 模块没有递归功能(处理嵌套结构),我将使用 pypi/regex 模块代替:

    import regex
    
    pat = r'''(?xms)
        \b explore:
        [^\S\r\n]* # optional horizontal whitespaces
        [^\n{]* # possible content of the same line
        # followed by two possibilities
        (?: # the content stops at the end of the line with a ;
            ; [^\S\r\n]* $
          | # or it contains curly brackets and spreads over eventually multiple lines
            ( # group 1
                {
                    [^{}"]*+ # all that isn't curly brackets nor double quotes
                    (?:
                        " [^\\"]*+ (?: \\. [^\\"]* )*+ " # contents between quotes
                        [^{}"]*
    
                      |
                        (?1) # nested curly brackets, recursion in the group 1
                        [^{}"]*
                    )*+
                }
            )
        )'''
    
    results = [x.group(0) for x in regex.finditer(pat, yourstring)]
    

    demo

    为了更严格,您可以添加对单引号字符串的支持,并使用(*SKIP)(*FAIL) 构造防止模式开头的“explore:”不在字符串中。

    【讨论】:

      【解决方案2】:

      虽然它在 Regex 中是可行的,但您应该使用能够理解格式的解析器,因为 Regex 解决方案非常脆弱。

      话虽如此,下面是一个启用了 DOTALL 模式的正则表达式解决方案(. 匹配任何字符,包括换行符):

      re.findall(r'explore:.*?\}', text, re.DOTALL)
      
      • explore: 匹配字面意思
      • .*?\} 非贪婪匹配到下一个 }

      示例:

      In [1253]: text = '''explore: character_balance {} 
            ...: explore: tower_ends { 
            ...:   label: "Tower Results" 
            ...:   join: activity_type { 
            ...:       relationship: many_to_one 
            ...:       type: inner 
            ...:       sql_on: ${activity_type.activity_name}=${wba_fact_activity.activity_name} ;; 
            ...:   } 
            ...: } 
            ...: explore: seven11_core_session_start {}'''                                                                                                                                                        
      
      In [1254]: re.findall(r'explore:.*?\}', text, re.DOTALL)                                                                                                                                     
      Out[1254]: 
      ['explore: character_balance {}',
       'explore: tower_ends {\n  label: "Tower Results"\n  join: activity_type {\n      relationship: many_to_one\n      type: inner\n      sql_on: ${activity_type.activity_name}',
       'explore: seven11_core_session_start {}']
      

      【讨论】:

        【解决方案3】:

        您可以使用带有前瞻断言的非贪婪匹配来检查是否存在另一个explore: 或字符串的结尾。试试:

        'explore:.*?(?=explore|$)'

        【讨论】:

          猜你喜欢
          • 2022-08-18
          • 1970-01-01
          • 1970-01-01
          • 2022-07-14
          • 1970-01-01
          • 1970-01-01
          • 2011-12-31
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多