2016-03-14 4 views
1

у меня есть что-то вроде этогоPyparsing с дополнительным на левой

IDENTIFIER = Word(alphas + '_', alphanums + '_') #words 
GENERIC_TYPE = Regex('[a-zA-Z_]+[a-zA-Z0-9_]*(\<[a-zA-Z0-9_]+\>)?') #List<string> or int 
AMF = Keyword('public') | Keyword('private') | Keyword('protected') #method modifier 
SFMF = Optional(Keyword('static')) & Optional(Keyword('final')) #static and final modifiers 

Для этого примера:

res = (Optional(AMF) + 
     SFMF + 
     IDENTIFIER).parseString('Method') 
print(res) 

он печатает: ['Method'], но если добавить Optional(GENERIC_TYPE):

res = (Optional(AMF) + 
     SFMF + 
     Optional(GENERIC_TYPE) + 
     IDENTIFIER).parseString(text) 
print(res) 

он печатает ['int', 'Method'] для text='int Method' BUT вызывает исключение для 'final Method' (или просто 'Method'):

pyparsing.ParseException: Expected W:(abcd...,abcd...) (at char 12), (line:1, col:13) 

Похоже Pyparsing не видит факультативную вещи, потому что если GENERIC_TYPE не является обязательным (как много вещей перед ним) он должен пойти дальше и разобрать IDENTIFIER часть.

UPDATE:

Проблема, кажется, в логике анализа. Если есть два одинаковых шаблона, а один из них - Необязательный, тогда анализатор не проверяет, является ли он вторым. Например:

m = Optional('M') + Literal('M') 
m.parseString('M') 

синтаксический анализатор совпадает с «M» в первой части, а затем пропускает неопциональные Буквальное часть.

Итак, теперь я могу разобрать его так, чтобы он соответствовал второму. Это может быть не конец строки или строки, поэтому я не могу использовать это.

ответ

2

Я бы сказал: «GENERIC_TYPE должен следовать идентификатор». Таким образом, чтобы прояснить вопрос с грамматикой, переписать res как:

res = (Optional(AMF) + 
     SFMF + 
     Optional(GENERIC_TYPE + FollowedBy(IDENTIFIER)) + 
     IDENTIFIER).parseString(text) 

Вы также можете написать это как:

res = (Optional(AMF) + 
     SFMF + 
     (GENERIC_TYPE + IDENTIFIER | IDENTIFIER)).parseString(text) 

Pyparsing делает не делать какие-либо предпросмотр как регулярное выражение будет делать, вам должны включать его в определение грамматики явно.

Кроме того, поскольку IDENTIFIER будет соответствовать любой строке символов, вы можете определить выражение, как «ключевое слово», что соответствует всем языковым ключевым словам, а затем определить IDENTIFIER как:

keyword = MatchFirst(map(Keyword,"public private protected static final".split())) 
IDENTIFIER = ~keyword + Word(alphas + '_', alphanums + '_') 

Наконец, вы можете хотите, чтобы GENERIC_TYPE обрабатывал больше, чем просто простые определения container<type>, например Map<String,String>, Map<String,List<String>> или даже Map<String,Map<String,Map<String,Map<String,Map<String,String>>>>>.

Это будет анализировать все те:

GENERIC_TYPE = Group(IDENTIFIER + nestedExpr('<', '>', content=delimitedList(IDENTIFIER))) 
+0

Спасибо большое! Больше, чем я хотел. Я знал, что решение есть где-то. Это круто!) Я хотел бы добавить, что я переопределил GENERIC_TYPE на 'g = Forward()' 'g << Word (alphas + '_', alphanums + '_') + Дополнительно (Подавить ('<') + Group (g) + Необязательный (Подавить (',') + Group (g)) + Подавить ('>')) 'возможно, это будет полезно для кого-то. – fantomasdnb

Смежные вопросы