Создание списка Lexer/Parser

Мне нужно создать лексер / парсер, который имеет дело с входными данными переменной длины и структуры.

Скажем, у меня есть список зарезервированных ключевых слов:

keyWordList = ['command1', 'command2', 'command3']

и строка ввода пользователя:

userInput = 'The quick brown command1 fox jumped over command2 the lazy dog command 3'
userInputList = userInput.split()

Как бы я пошел о написании этой функции:

INPUT:

tokenize(userInputList, keyWordList)

OUTPUT:
[['The', 'quick', 'brown'], 'command1', ['fox', 'jumped', 'over'], 'command 2', ['the', 'lazy', 'dog'], 'command3']

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

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

4 ответа

Решение

Попробуй это:

keyWordList = ['command1', 'command2', 'command3']
userInput = 'The quick brown command1 fox jumped over command2 the lazy dog command3'
inputList = userInput.split()

def tokenize(userInputList, keyWordList):
    keywords = set(keyWordList)
    tokens, acc = [], []
    for e in userInputList:
        if e in keywords:
            tokens.append(acc)
            tokens.append(e)
            acc = []
        else:
            acc.append(e)
    if acc:
        tokens.append(acc)
    return tokens

tokenize(inputList, keyWordList)
> [['The', 'quick', 'brown'], 'command1', ['fox', 'jumped', 'over'], 'command2', ['the', 'lazy', 'dog'], 'command3']

Что-то вроде этого:

def tokenize(lst, keywords):
    cur = []
    for x in lst:
        if x in keywords:
            yield cur
            yield x
            cur = []
        else:
            cur.append(x)

Это возвращает генератор, так что оберните ваш вызов в один list,

Это легко сделать с помощью некоторого регулярного выражения:

>>> reg = r'(.+?)\s(%s)(?:\s|$)' % '|'.join(keyWordList)
>>> userInput = 'The quick brown command1 fox jumped over command2 the lazy dog command3'
>>> re.findall(reg, userInput)
[('The quick brown', 'command1'), ('fox jumped over', 'command2'), ('the lazy dog', 'command3')]

Теперь вам просто нужно разделить первый элемент каждого кортежа.

Для более чем одного уровня глубины регулярное выражение не может быть хорошим ответом.

На этой странице вы можете выбрать несколько хороших парсеров: http://wiki.python.org/moin/LanguageParsing

Я думаю, что Лепл хороший.

Или взгляните на PyParsing. Довольно хорошая маленькая комбинация лекс-парсера

Другие вопросы по тегам