Разбирайте и группируйте несколько элементов вместе с помощью Pyparse

Это построение на Создайте простой синтаксический анализатор, способный анализировать различные форматы даты с помощью PyParse

У меня есть синтаксический анализатор, который должен сгруппировать одного или нескольких пользователей в список. Итак, a.parser('show abc, xyz commits from "Jan 10,2015" to "27/1/2015"') должен сгруппировать два имени пользователя в список [abc,xyz]

Для пользователей у меня есть:

keywords = ["select", "show", "team", "from", "to", "commits", "and", "or"]
    [select, show, team, _from, _to,  commits, _and, _or] = [ CaselessKeyword(word) for word in keywords ]

user = Word(alphas+"."+alphas)
user2 = Combine(user + "'s")
users = OneOrMore((user|user2))

А грамматика такая

bnf = (show|select)+Group(users).setResultsName("users")+Optional(team)+(commits).setResultsName("stats")\
    +Optional(_from + quotedString.setParseAction(removeQuotes)('from') +\
    _to + quotedString.setParseAction(removeQuotes)('to'))

Это ошибочно. Может ли кто-нибудь направить меня в правильном направлении. Кроме того, есть ли в pyparse способ выборочно решить, к какой группе должно относиться слово. Я имею в виду, что автономный «xyz» должен идти в моем списке пользователей. Но «команда xyz» должна идти в списке команд. Если указана необязательная команда ключевых слов, pyparse должен сгруппировать ее по-другому.

Я не смог найти то, что я ищу в Интернете. Или, может быть, я не правильно сформулировал свой вопрос в Google?


person Fizi    schedule 29.01.2015    source источник


Ответы (1)


Вы на правильном пути, смотрите встроенные комментарии в этом обновлении вашего парсера:

from pyparsing import *

keywords = ["select", "show", "team", "from", "to", "commits", "and", "or"]
[select, show, team, _from, _to,  commits, _and, _or] = [ CaselessKeyword(word) for word in keywords ]

# define an expression to prevent matching keywords as user names - used below in users expression
keyword = MatchFirst(map(CaselessKeyword, keywords))

user = Word(alphas+"."+alphas)  # ??? what are you trying to define here?
user2 = Combine(user + "'s")
# must not confuse keywords like commit with usernames - and use ungroup to 
# unpack single-element token lists
users = ungroup(~keyword + (user|user2))

#~ bnf = (show|select)+Group(users).setResultsName("users")+Optional(team)+(commits).setResultsName("stats") \
    #~ + Optional(_from + quotedString.setParseAction(removeQuotes)('from') +
                    #~ _to + quotedString.setParseAction(removeQuotes)('to'))

def convertToDatetime(tokens):
    # change this code to do your additional parsing/conversion to a Python datetime
    return tokens[0] 
timestamp = quotedString.setParseAction(removeQuotes, convertToDatetime)

# similar to your expression
# - use delimitedList instead of OneOrMore to handle comma-separated list of items
# - add distinction of "xxx team" vs "xxx"
# - dropped expr.setResultsName("name") in favor of short notation expr("name")
# - results names with trailing '*' will accumulate like elements into a single
#   named result (short notation for setResultsName(name, listAllValues=True) )
# - dropped setResultsName("stats") on keyword "commits", no point to this, commits must always be present
#
bnf = ((show|select)("command") + delimitedList(users("team*") + team | users("user*")) + commits + 
            Optional(_from + timestamp('from') + _to + timestamp('to')))

test = 'show abc, def team, xyz commits from "Jan 10,2015" to "27/1/2015"'

print bnf.parseString(test).dump()

Отпечатки:

['show', 'abc', 'def', 'team', 'xyz', 'commits', 'from', 'Jan 10,2015', 'to', '27/1/2015']
- command: show
- from: Jan 10,2015
- team: ['def']
- to: 27/1/2015
- user: ['abc', 'xyz']
person PaulMcG    schedule 30.01.2015
comment
Большое спасибо. Я очень ценю, что вы нашли время, чтобы помочь мне. Что касается определения пользователей, это то, как определяются имена пользователей. Это всегда имя.фамилия и, следовательно, мое определение. Если у меня возникнут дополнительные вопросы, мне продолжить эту тему или создать отдельный пост? - person Fizi; 30.01.2015
comment
Word(alphas+"."+alphas) примет любую группу слов, состоящую из букв и '.', например, abc...d.ddd. Если вы хотите firstname.lastname, измените на Combine(Word(alphas) + '.' + Word(alphas)). Или, чтобы соответствовать вашему тестовому коду, используйте Combine(Word(alphas) + Optional('.' + Word(alphas))) SO, чтобы избежать длинных цепочек комментариев — если у вас есть дополнительные вопросы о pyparsing, открывайте новые сообщения. - person PaulMcG; 31.01.2015