2016-10-08 5 views
2

Я хочу совместить слово, которое заканчивается на _foo или _bar. Я написал это:Нежелательное совпадение Слова в pyparsing?

identifier = Word(alphanums + '_') 
string  = identifier + Suppress('_') + oneOf('foo bar') 

К сожалению, я понял identifier жаден и потребляют все ключевые слова.

Как я могу заставить identifier не жадничать?

$ string.parseString('a_keyword_foo') 
ParseException: Expected "_" (at char 13), (line:1, col:14) 

Некоторые допустимые ключевые слова:

a_keyword_foo   # ['a_keyword', 'foo'] 
foo_bar_foo   # ['foo_bar', 'foo'] 
bar_bar    # ['bar',  'bar'] 

Некоторые недействительные ключевые слова:

keyword_foo_foobar 
2keywords_bar   # The leading number is perhaps another question... 
foo _bar 
_foo 
+0

Нежелательное соответствие обсуждается по адресу: http://stackoverflow.com/questions/15938540/pyparsing-non-greedy-match. Удачи! – Jurgenfd

+0

@ Jurgenfd, я прочитал это. Что я упустил? – nowox

ответ

2

После того, как вы знаете, за то, что вы ищете, вы можете использовать pp.SkipTo:

In [38]: foo_or_bar = Literal('foo') | Literal('bar') 

In [39]: string = SkipTo(Literal('_') + foo_or_bar) + Literal('_') + foo_or_bar 

In [42]: string.parseString('frumpy _foo') 
Out[42]: (['frumpy ', '_', 'foo'], {}) 

К сожалению, вы также получите такое поведение, хотя:

In [44]: string.parseString('frumpy _foo _foo') 
Out[44]: (['frumpy ', '_', 'foo'], {}) 

в случае картина может оказаться более чем один раз.

Проблема заключается в том, что pyparsing не выполняет поиска. Если вас беспокоит второй случай, вам придется определить его как одну или несколько вещей, заканчивающихся символом underscore + foo или bar (как указано выше), а затем взять последний.

+0

Ничего, я не знал 'SkipTo', но' frumpy _foo' не одно ключевое слово, но 2. – nowox

+1

@nowox Я не понимаю ваш комментарий (или вопрос). Можете ли вы добавить к своим вопросным входам и требуемым выходам? –

+0

Я добавил несколько примеров к вопросу. – nowox

1

Если у вас есть/может переключиться на повторное API вы можете использовать не-жадные соответствия есть:

import re 
    p = re.compile (r"""([a-z_]+?)  # lazy matching identifier 
         _ (bar|foo)  # _ with foo or bar 
     """, re.VERBOSE) 
    subject_string = 'a_hello_foo' 
    m = p.match(subject_string) 
    print "groups:", m.groups() 
    print "group 1:", m.group(1) 

В Pyparsing есть также возможность использовать регулярное выражение.

+0

Я бы, вероятно, воспользовался здесь с помощью 'pyparsing.Regex', хотя вы также могли использовать обычное старое Word и добавлять условие, чтобы принимать только те слова, которые заканчиваются на« _bar »или« _foo », что-то вроде' string = identifier() .addCondition (lambda t: t [0] .endswith ('_ foo') или t [0] .endswith ('_ bar') ' – PaulMcG

+0

yes, а затем postprocess, чтобы обрезать конечные символы. Должно быть легко ;-) – Jurgenfd

+1

??? - никакой последующей обработки не требуется. Выражение Word будет получать только тело идентификатора, а не любые дополнительные символы. И я уверен, что OP * хотел * окончания '_foo' или '_bar', поэтому не нужно их обрезать. – PaulMcG