Как извлечь запрос регулярного выражения до конкретного слова? - PullRequest
0 голосов
/ 01 июля 2019

Я пытаюсь извлечь определенные данные из 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:\s[^;]*'.Но это останавливается на ';', при условии, что он есть.

Как бы я изменил это так, чтобы он убрал все между «исследовать» и «исследовать»?Просто заменив ';'в моем регулярном выражении «исследовать» вместо этого останавливается всякий раз, когда он находит букву, которая соответствует чему-либо в [e, x, p, l, o, r, e] - что не является тем поведением, которое я хочу.Снятие квадратных скобок и ^ в конечном итоге разбивает все так, что он не может запрашивать несколько строк.

Что мне здесь делать?

Ответы [ 3 ]

1 голос
/ 02 июля 2019

Наивный подход заключается в достижении следующего слова «исследовать». Но если по какой-либо причине строковое значение содержит это слово, вы получите неправильные результаты. Та же проблема, если вы пытаетесь прекратить использовать фигурные скобки, когда строка содержит вложенные скобки.

Вот почему я предлагаю более точное описание синтаксиса вашей строки, которая учитывает строки и вложенные фигурные скобки. Поскольку модуль 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)]

демо

Чтобы быть более строгим, вы можете добавить поддержку для строки в одинарных кавычках, а также запретить использование «explore:» в начале шаблона в строке, используя конструкцию (*SKIP)(*FAIL).

0 голосов
/ 01 июля 2019

Хотя в Regex это выполнимо, вам следует использовать синтаксический анализатор, который понимает формат, поскольку решение Regex будет довольно хрупким.

Сказав это, вот решение Regex с режимом DOTALL (, где . соответствует любому символу, включая символ новой строки ):

re.findall(r'explore:.*?\}', text, re.DOTALL)
  • explore: соответствует буквально
  • .*?\} не жадно соответствует следующему }

* * Пример тысячи двадцать-одина: * ** 1023 тысячу двадцать две *

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 {}']
0 голосов
/ 01 июля 2019

Вы можете использовать не жадное совпадение с проверочным утверждением, чтобы проверить наличие другого explore: или конца строки. Попробуйте:

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

...