рекурсивное вложенное выражение в Python - PullRequest
3 голосов
/ 01 февраля 2010

Я использую Python 2.6.4.

У меня есть несколько операторов выбора в текстовом файле, и мне нужно извлечь имена полей из каждого запроса выбора. Это было бы легко, если бы некоторые поля не использовали вложенные функции, такие как to_char () и т. Д.

Учитывая поля оператора выбора, которые могут иметь несколько вложенных скобок, таких как "ltrim (rtrim (to_char (base_field_name, format))) renamed_field_name" или простой случай использования только "base_field_name" в качестве поля, возможно ли использовать повтор Python модуль для написания регулярных выражений для извлечения base_field_name? Если так, то как бы выглядело это регулярное выражение?

Ответы [ 6 ]

11 голосов
/ 01 февраля 2010

Регулярные выражения не подходят для анализа "вложенных" структур. Вместо этого попробуйте полноценный набор для разбора, такой как pyparsing - примеры использования pyparsing специально для синтаксического анализа SQL можно найти здесь и здесь , например (вам, несомненно, нужно взять примеры в качестве отправной точки и написать собственный код для разбора, но это определенно не так уж сложно).

2 голосов
/ 01 февраля 2010

Либо синтаксический анализатор, управляемый таблицей, как предлагает Алекс Мартелли, либо рукописный анализатор рекурсивного спуска Они не сложны и довольно полезны для написания.

2 голосов
/ 01 февраля 2010
>>> import re
>>> string = 'ltrim(rtrim(to_char(base_field_name, format))) renamed_field_name'
>>> rx = re.compile('^(.*?\()*(.+?)(,.*?)*(,|\).*?)*$')
>>> rx.search(string).group(2)
'base_field_name'
>>> rx.search('base_field_name').group(2)
'base_field_name'
1 голос
/ 01 февраля 2010

Вот действительно взломанный парсер, который делает то, что вы хотите.

Он работает, вызывая 'eval' для анализируемого текста, сопоставляя все идентификаторы с функцией, которая возвращает свой первый аргумент (я полагаю, это то, что вы хотите, учитывая ваш пример).

class FakeFunction(object):
    def __init__(self, name):
        self.name = name
    def __call__(self, *args):
        return args[0]
    def __str__(self):
        return self.name

class FakeGlobals(dict):
    def __getitem__(self, x):
        return FakeFunction(x)

def ExtractBaseFieldName(x):
    return eval(x, FakeGlobals())

print ExtractBaseFieldName('ltrim(rtrim(to_char(base_field_name, format)))')
1 голос
/ 01 февраля 2010

Это может быть достаточно хорошо:

import re
print re.match(r".*\(([^\)]+)\)", "ltrim(to_char(field_name, format)))").group(1)

Вам необходимо выполнить дальнейшую обработку. Например, выберите имя функции и извлеките имя поля в соответствии с сигнатурой функции.

.*(\w+)\(([^\)]+)\)
0 голосов
/ 01 февраля 2010

Вам действительно нужны регулярные выражения? Чтобы получить тот, который у вас есть, я бы использовал

  s[s.rfind('(')+1:s.find(')')].split(',')[0]

с 's', содержащим исходную строку.

Конечно, это не общее решение, но ...

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