pyparsing, как передать идентификаторы парсеру - PullRequest
1 голос
/ 13 июня 2019

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

Вместо identifiers = Literal('identifier1') | Literal('identifier2') | Literal('identifier whatever') у меня есть массив идентификаторов identifiers = ['identifier1', 'identifier2', 'identifier whatever', ... 'identifier I can not what'], которые мне нужно указать pyparsing для использования в качестве идентификаторов.

Это то, что я сделал до сих пор:

def __init__(self, idents):
    if isinstance(idents, list) and idents:
        for identifier in idents:
           // and this is where I got stuck
           // I tried:
           // identifiers = Literal(identifier) but this keeps only the lastone

Как мне этого добиться?

1 Ответ

1 голос
/ 14 июня 2019

Самый простой способ преобразовать список строк в список альтернативных выражений синтаксического анализа - это использовать oneOf:

import pyparsing as pp

color_expr = pp.oneOf(["red", "orange", "yellow", "green", "blue", "purple"])
# for convenience could also write as pp.oneOf("red orange yellow green blue purple")
# but since you are working with a list, I am show code using a list

parsed_colors = pp.OneOrMore(color_expr).parseString("blue orange yellow purple green green")

# use pprint() to list out results because I am lazy
parsed_colors.pprint()
sum(color_expr.searchString("blue 1000 purple, red red swan okra kale 5000 yellow")).pprint()

Печать:

['blue', 'orange', 'yellow', 'purple', 'green', 'green']
['blue', 'purple', 'red', 'red', 'yellow']

Итак oneOf(["A", "B", "C"])и версия с простой кнопкой oneOf("A B C") совпадает с Literal("A") | Literal("B") | Literal("C")

С oneOf следует помнить одну вещь: она не устанавливает границы слов

pp.OneOrMore(color_expr).parseString("redgreen reduce").pprint()

print:

['red', 'green', 'red']

, хотя начальные слова «красный» и «зеленый» не являются отдельными словами, а конечный «красный» - это только первая часть слова «уменьшить».Это именно то поведение, которое вы получите при использовании явного выражения, созданного с помощью Literal s.

Чтобы обеспечить ограничение слов, вы должны использовать класс Keyword, и теперь вам нужно использовать немного больше Python дляпостроить это.

  1. Вам нужно будет создать выражение Or или MatchFirst для ваших альтернатив.Обычно вы создаете их используя '^' или '|'операторы соответственно.Но чтобы создать одно из них, используя список выражений, вам нужно вызвать форму конструктора Or(expression_list) или MatchFirst(expression_list).

  2. Если у вас есть список строк, вы может просто создать Or(list_of_identifiers), но это по умолчанию приведет к преобразованию строк в литералы, и мы уже видели, что вы этого не хотите.

  3. Вместо этого используйтеваши строки для создания выражений Keyword с использованием понимания списка Python или выражения генератора и передачи его конструктору MatchFirst (MatchFirst будет более эффективным, чем Or, а сопоставление Keyword будет безопасно использовать с логикой короткого замыкания MatchFirst).Следующее все будет работать одинаково, с небольшими различиями в том, как последовательность ключевых слов создается и передается в конструктор MatchFirst:

    # list comprehension
    MatchFirst([Keyword(ident) for ident in list_of_identifiers])
    
    # generator expression
    MatchFirst(Keyword(ident) for ident in list_of_identifiers)
    
    # map built-in
    MatchFirst(map(Keyword, list_of_identifiers))
    

Вот пример соответствия цветов, переделанный с помощьюКлючевые слова.Обратите внимание, что цвета, встроенные в более крупные слова, теперь не совпадают:

colors = ["red", "orange", "yellow", "green", "blue", "purple"]
color_expr = pp.MatchFirst(pp.Keyword(color) for color in colors)
sum(color_expr.searchString("redgreen reduce skyblue boredom purple 100")).pprint()

Отпечатки:

['purple']
...