Как разобрать параметры из текста?

#python #regex

#python #регулярное выражение

Вопрос:

У меня есть текст, который выглядит как:

 ENGINE = CollapsingMergeTree (
    first_param
    ,(
        second_a
        ,second_b, second_c,
        ,second d), third, fourth)
  

Движок может быть другим (вместо свертывания MergeTree может быть другое word, заменяющее MergeTree, суммирующее MergeTree …), Но текст всегда в формате ENGINE = word (). Вокруг знака «=» может быть пробел, но это не обязательно.
Внутри круглых скобок находятся несколько параметров, обычно это одно слово и запятая, но некоторые параметры заключены в круглые скобки, как вторые в примере выше.
Разрывы строк могут быть где угодно. Строка может заканчиваться запятой, круглой скобкой или чем-либо еще.

Мне нужно извлечь n параметров (я не знаю, сколько заранее). В приведенном выше примере есть 4 параметра:

  1. first = first_param

  2. second = (second_a, second_b, second_c, second_d) [извлечь в круглых скобках]

  3. третий = третий

  4. четвертый = четвертый

Как это сделать с помощью python (regex или чего-либо еще)?

Ответ №1:

Вы, вероятно, захотите использовать правильный синтаксический анализатор (и поэтому посмотрите, как вручную выполнить синтаксический анализатор для простого языка) для любого языка, который есть, но поскольку то немногое, что вы показываете здесь, выглядит совместимым с Python, вы могли бы просто проанализировать его, как если бы это был Python, используя ast модуль (из стандартной библиотеки), а затем манипулировать результатом.

Ответ №2:

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

 #Import the module for regular expressions
import re

#Text to search. I CORRECTED IT A BIT AS YOUR EXAMPLE SAID second d AND second_c WAS FOLLOWED BY TWO COMMAS. I am assuming those were typos.
text = '''ENGINE = CollapsingMergeTree (
    first_param
    ,(
        second_a
        ,second_b, second_c
        ,second_d), third, fourth)'''

#Regex search pattern. re.S means . which represents ANY character, includes n (newlines)
pattern = re.compile('ENGINE = CollapsingMergeTree ((.*?),((.*?)),(.*?), (.*?))', re.S) #ENGINE = CollapsingMergeTree ((.*?),((.*?)), (.*?), (.*?))

#Apply the pattern to the text and save the results in variable 'result'. result[0] would return whole text.
#The items you want are sub-expressions which are enclosed in parentheses () and can be accessed by using result[1] and above
result = re.match(pattern, text)

#result[1] will get everything after theparenteses after CollapsingMergeTree until it reaches a , (comma), but with whitespace and newlines. re.sub is used to replace all whitespace, including newlines, with nothing
first = re.sub('s', '', result[1])

#result[2] will get second a-d, but with whitespace and newlines. re.sub is used to replace all whitespace, including newlines, with nothing
second = re.sub('s', '', result[2])

third = re.sub('s', '', result[3])

fourth = re.sub('s', '', result[4])

print(first)
print(second)
print(third)
print(fourth)
  

ВЫВОД:

 first_param
second_a,second_b,second_c,second_d
third
fourth
  

Объяснение регулярных выражений:
= Экранирует управляющий символ, который регулярное выражение интерпретировало бы как означающий что-то особенное. Подробнее здесь.

( = Экранирующие скобки

() = Отметьте выражение в круглых скобках как подгруппу. Смотрите результат [1] и так далее.

. = Соответствует любому символу (включая новую строку, из-за re.S)

* = Соответствует 0 или более вхождениям предыдущего выражения.

? = Соответствует 0 или 1 вхождению предыдущего выражения.

ПРИМЕЧАНИЕ: *? комбинированный называется повторением без повторения, что означает, что предыдущее выражение сопоставляется только один раз, а не снова и снова.

Я не эксперт, но я надеюсь, что правильно понял объяснения.

Я надеюсь, что это поможет.

Комментарии:

1. Я забыл сказать, что вместо CollapsingMergeTree может быть 10 разных слов (ReplacingMergeTree, SummingMergeTree), но это всегда в формате ENGINE = *MergeTree(param1, param2, …, paramN). Движок и знак равенства могут быть разделены пробелом, но это не обязательно. Кроме того, параметры должны оставаться такими, какие они есть, поэтому вторым параметром должно быть «(second_a, second_b, second_c, second_d)» вместо «second_a, second_b, second_c, second_d». Количество параметров также варьируется.

2. Допустим, я могу извлечь все между первой и последней круглыми скобками, поэтому я должен извлечь различное количество параметров, и некоторые из них могут быть в круглых скобках.

3. Попробуйте этот шаблон регулярных выражений. Он не ищет конкретное слово после ENGINE = и оставляет круглые скобки вокруг second_ a-d. 'ENGINE =.*?((.*?),(.*?)),(.*?), (.*?))'

4. Это работает, если текст находится в одной строке, и если я знаю, сколько параметров будет заключено в круглые скобки. Я ищу модульное решение, которое будет извлекать параметры, разделенные запятыми, и соблюдать скобки.

5. На этом этапе я рекомендую вам взглянуть на то, как самостоятельно выполнять поиск по регулярным выражениям, если вы хотите пойти по этому пути, поскольку вы знаете сценарий, который используете лучше, чем кто-либо другой. Я надеюсь, что смог дать вам несколько полезных инструментов для этого.