PyParsing ИЛИ оператор - PullRequest
       15

PyParsing ИЛИ оператор

3 голосов
/ 27 апреля 2011

Это будет очень просто, но я пытаюсь сопоставить один из двух шаблонов:

"GET /ligonier-broadcast-media/mp3/rym20110421.mp3 HTTP/1.1"

или

-

Я пробовал кое-чтокак это:

key = Word(alphas + nums + "/" + "-" + "_" + "." + "?" + "=" + "%" + "&")

uri = Or("-" | Group(
                   Suppress("\"") +
                   http_method +
                   key.setResultsName("request_uri") +
                   http_protocol +
                   Suppress("\"")
               )
      )

Но это не похоже.Я не совсем уверен, как использовать Or (), если я должен быть Group (), или что.Я знаю, что аргументы, предоставляемые в классе Group (), работают, если они вызываются отдельно, но мне действительно нужна либо строка тире, либо строка URI в кавычках, а не одна.

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

Ответы [ 2 ]

19 голосов
/ 27 апреля 2011

Как правило, классы Or, And, MatchFirst и Each очень редко используются открыто при преобразовании. Рекомендуемый стиль - использовать их аналогичные операторские перегрузки. В вашем случае вы используете обе формы, и это только мешает вам.

Вот ваше выражение лица после небольшой уборки:

key = Word(alphanums + "/-_.?=%&")
QUOT = Suppress('"')
uri = ("-" | QUOT
             + http_method
             + key("request_uri")
             + http_protocol
             + QUOT
      )

Аргументами Word являются строки символов, представляющие наборы разрешенных символов. Если используется только один аргумент (как в вашем случае), то строка интерпретируется как просто набор символов, которые могут быть проанализированы как часть Word. Если заданы 2 строки, то первая представляет набор допустимых начальных символов, а вторая представляет набор допустимых символов тела (полезно при определении чего-то вроде имени переменной, которое, например, в Python допускает только альфы и «_» для начальный символ, но также допускает числовые цифры в теле. Это будет Word(alphas+'_', alphanums+'_'). Поскольку аргументы Word являются просто строками, нет необходимости отдельно добавлять "/" + "-" + "_" + ..., просто объединить их в одну строку.

'|' Разграничение операторов допускает альтернативы, генерируя выражение MatchFirst. Он называется MatchFirst, потому что анализатор прекратит попытки после совпадения первого заданного выражения. Так что если при разборе строки «abc» с помощью Word(alphas) | Word(nums), pyparsing даже не попытается сопоставить выражение Word(nums) - первое альтернативное совпадение. Это становится сложнее, если есть некоторые совпадения в том, что вы хотите. Допустим, вы хотите сопоставить слова букв, слова альфа или слова букв и альфа, и вы хотите проанализировать строку «abc123». Этот парсер:

Word(alphas) | Word(nums) | Word(alphanums)

проанализирует открывающий 'abc' строки с ведущим Word(alphas). Мы часто можем решить такую ​​проблему, переставив альтернативы, такие как:

Word(alphanums) | Word(alphas) | Word(nums)

но не во всех случаях так легко рефакторинг. Поэтому pyparsing также поддерживает выражение Or, определенное с помощью оператора «^» (который я выбрал, потому что «^» напоминает мне пару разделителей рисовальщика для измерения длины). Выражение Or пытается применить all указанных альтернатив и выбирает longon , соответствующий одному. Таким образом, вы можете написать мой маленький тестовый пример как:

Word(alphas) ^ Word(nums) ^ Word(alphanums)

и теперь pyparsing не остановится при сопоставлении «abc», но попробует все альтернативы и в конечном итоге выберет третий вариант, соответствующий «abc123», потому что он дает более длинное совпадение.

Для определения URI нет необходимости выполнять или сопоставлять. Нет никакого способа, которым парсер будет путать начальный '-' с командной строкой HTTP в кавычках. Таким образом, используя MatchFirst, который вы сделали с помощью '|' оператор, вполне адекватный.

Некоторые другие предметы:

  • Не пишите "\"" на Python, если можете помочь. По этой причине Python поддерживает оба символа кавычек. Используйте '"' вместо этого. Обратная косая черта предназначена для программистов на C и имен файлов Windows.

  • expr.setResultsName("name") был упрощен до expr("name"), начиная с 1.4.6. Сокращенный синтаксис действительно помогает удобочитаемости определений вашего синтаксического анализатора.

  • Используйте Группу, только если вы хотите сохранить некоторую структуру в своих результатах или если у вас есть повторяющаяся структура, которая имеет некоторое внутреннее выражение с именем результатов. На самом деле не требуется для вашего анализатора, он просто добавляет еще одну упаковку контейнера списка к результатам, требуя дополнительного индекса [0] для доступа к вашим проанализированным данным.

(Если вы do решите, что хотите явно вызвать Or, And и т. Д., Обязательно передайте список выражений, а не просто перечисляйте их в качестве аргументов для конструктор выражений - см. Почему упорядоченный выбор в pyparsing не удался для моего варианта использования? о том, как такая опечатка может все испортить, поэтому я рекомендую использовать арифметические операторы для составления ваших парсеров.)

1 голос
/ 27 апреля 2011

Я думаю, что вы хотите ...

from pyparsing import oneOf
# more code here
uri = oneOf(["-", <insert long match expr here>])`
uri.matchString(someStringVar)
...