Xgu.ru теперь в Контакте  — приходите и подключайтесь.
Пока мы работаем над следующими видео, вы можете подключиться в Контакте. Познакомимся и обсудим новые страницы и ролики.

Vk-big.pngYoutube-big.jpeg

pyparsing

Материал из Xgu.ru

Перейти к: навигация, поиск
stub.png
Данная страница находится в разработке.
Эта страница ещё не закончена. Информация, представленная здесь, может оказаться неполной или неверной.

Если вы считаете, что её стоило бы доработать как можно быстрее, пожалуйста, скажите об этом.

Автор: Владимир Кореньков

Содержание


[править] Pyparsing — модуль синтаксического анализа для языка Python

Для языка Python создано достаточно большое количество синтаксических анализаторов. В данной статье будет рассмотрен один из них — pyparsing.

Подобно регулярным выражениям, последовательность работы с данной библиотекой содержит три этапа:

  • определение грамматики исходного текста;
  • применение данной грамматики к исходному тексту (как правило это вызов функции parseString или scanString);
  • анализ полученных в виде списка результатов.

[править] Постановка задачи

Задача формулируется следующим образом. Практически все CAM-системы результат генерирования траекторий перемещения инструмента, а также некоторую технологическую информацию, сохраняют в промежуточный формат, который получил обобщенное название CLData.

В принципе существует его описание[1], однако каждая система в этот формат привносит свои особенности, поэтому CLData нельзя назвать полностью "стандартным".

Между CLData и конкретной стойкой ЧПУ находится программа, под общим названием "постпроцессор" (применительно к вычислительной технике, эту программу можно было бы назвать драйвером). Постпроцессор должен решать две глобальные задачи (мелочь -- пока не в счет):

  • преобразование форматов (каждая стойка ЧПУ понимает только свойственный ей формат команд, так называемый G-код);
  • математические преобразования (см. python/CAM/postporcessor).

Решение же данных задач невозможно без разбора исходного CLData-файла. Собственно этим мы и займемся в данной статье.

[править] Исходные данные

Исходный файл, с которым мы будем работать дальше, имеет следующий вид:


Файл code.cldata представляет собой последовательность команд, состоящих в общем случае из пары: Имя — аргументы (могут быть необязательными), разделенных разного рода разделителями. Например:

GOTO / x, y, z [i, j, k]

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


[править] Функции обработки входного текста

Для того чтобы не только правильно описать грамматику, а и вообще понять ЧТО мы хотим описать, сначала следует выяснить как будет обрабатываться текст.

Допустим имеется некая переменная pattern -- шаблон (описание грамматики), на соответствие которому проверяется текст. Проверка выполняется методом searchString (для простоты изложения вопроса, пока не будем рассматривать все разнообразие методов):

result = pattern.searchString(text)

Отсюда вытекают два возможных варианта:

  • переменная text представляет собой одну строку, в которую помещено все содержимое исходного файла
  • переменной text в процессе чтения файла (в цикле) присваивается по отдельной строке данного файла



Выбранный вариант будет предопределять содержимое переменной pattern.

Применительно к рассматриваемому примеру, второй вариант будет требовать обязательной предварительной обработки текста -- приведения файла к виду, одна строка -- одна команда. В противном случае будет путаница, поскольку заранее неизвестно в каком именно месте САМ-система поставит разрыв CLData-строки. Для первого способа эта предобработка является необязательной, но желаемой, т.к. значительно упрощает описание pattern.

Таким образом, для дальнейшего рассмотрения примем первый вариант обработки текста.

[править] Описание грамматики

Немного терминологии: понятие "грамматика" — это способ описания формального языка, который в данном случае представлен набором управляющих команд файла code.cldata. Последовательности допустимых символов языка, несущих некоторою смысловую нагрузку, принято называть "лексемами". В свою очередь, лексемы формируются из отдельных групп символов — "токенов".

Таким образом, процесс описания грамматики следует начинать с формирования "кирпичиков".


[править] Синтаксис

Согласно официальной документации, токены можно сформировать с помощью следующих функций.

Literal() поиск точного совпадения строки (допускается писать строку просто в кавычках -- см. примеры)
CaselessLiteral() создаётся искомой строкой, но без проверки регистра; результаты всегда превращаются в определяющий литерал, а не остаются такими, как они записаны во входной строке
Keyword() похоже на Literal, но обязательно должен сопровождаться пробельным символом, символом пунктуации или другим не ключевым словом; защищает от неправильного распознавания неключевых слов, которые начинаются ключевым словом
CaselessKeyword() аналогично Keyword, только без учёта регистра
Word() строка, не содержащая символа пробела и/или табуляции; формируется из букв, цифр и пр. (например, 'Hello', 'user_name', '$a' и т.д.)
CharsNotIn() Похоже на Word_, but matches characters not in the given constructor string (accepts only one string for both initial and body characters); also supports min, max, and exact optional parameters.
Regex() полноценные конструкции, содержащие регулярные выражения; принимают необязательные параметры флагов аналогичных модулю re; если выражение включает именованные поля, то они будут возвращены в ParseResults
QuotedString() определяет различные разделители (в дополнение к dblQuotedString и sglQuotedString)
SkipTo() позволяет при поиске пропускать несовпадающие фрагменты (выполняется предпросмотр)
White() аналогично Word, но включает проверку с символами пробела (по умолчанию pyparsing игнорирует пробелы, поэтому данная функция может быть полезна при разборе текста, строки которого содержит ведущие символы табуляции/пробелов)
Empty() выражение, не содержащее символов — null
NoMatch() противоположно Empty


Функции в качестве аргументов, помимо обычных символов, могут принимать константы или их комбинации:


alphas строка, состоящая из букв алфавита
nums строка, состоящая из цифр
alphanums строка, состоящая из букв и цифр
alphas8bit строка, состоящая из 8-битных символов
printables все печатаемые символы, за исключением пробела (' ')
restOfLine() все печатаемые символы, от места обявления до конца строки
empty соответствует глобальному Empty()
sglQuotedString строка символов, заключенная в кавычки " ' ", может содержать пробелы, но не знак конца строки
dblQuotedString  ??? (согласно документации, определение аналогично sglQuotedString)
quotedString комбинация предыдущих двух: 'sglQuotedString | dblQuotedString'
cStyleComment() блок текста (комментариев), помещенный между ' /* ' и ' */ '; может занимать несколько строк, но не поддерживает вложенность комментариев
htmlComment() блок текста (комментариев), помещенный между ' <!-- ' и ' --> '; может занимать несколько строк, но не поддерживает вложенность комментариев
commaSeparatedList() аналогично delimitedList, однако список выражений может принимать любые значения


Длина символов или констант ограничивается параметрами:


min ограничение минимальной длины строки
max ограничение максимальной длины строки
exact указание точной длины строки
srange задание диапазона символов


Комбинирование функции или константы выполняется с помощью выражений:


And() логическое И (может быть заменено символом '+')
Or() логическое ИЛИ (может быть заменено символом '^')
MatchFirst() каждое соответствие фрагмента текста шаблону рассматривается слева направо (может быть заменено символом '|')
Each() аналогичен оператору And, с той особенностью, что каждое соответствие фрагмента текста шаблону рассматривается не последовательно, а в произвольном порядке (может быть заменено '&')
Optional() поиск фрагмента текста, который может встречаться или не встречаться (например, необязательный параметр функции)
ZeroOrMore() фрагмент текста, соответствующий аргумент (шаблону) может встречаться ноль или более раз
OneOrMore() фрагмент текста, соответствующий аргумент (шаблону) может встречаться один или более раз
FollowedBy() предпросмотр совпадения шаблона (функция всегда возвращает NULL и лишь подтверждает совпадение)
NotAny() отрицание выражения заданного шаблоном (может быть заменено '~')


[править] Примеры составления шаблонов

Word(nums + ".-") число, определенное как слово, которое может состоять из цифр и/или точки и/или знака минуса (например, "10" или "10.5", или "-10.5")
Literal("#") + restOfLine любой текст от символа "#" включительно до символа конца строки (чаще всего применяется для поиска закомментированного текста)
Word( "xyz", max=1 ) + Literal("=").suppress() одна из букв x, y или z и стоящий за ней знак равенства (последний в список результатов поиска не будет включен)
"[" + Word(alphas.upper()) + "]" любые буквы верхнего регистра, заключенные в скобки, например "[ABC]" (метод upper() и lower() могу применяться к константам, функциям или группам); скобки, заключенные в кавычки, раскрываются как Literal
Word( srange("[A-N]"), exact=6) слово, состоящее из шести строчных букв из диапазона A-N, например "DEBIAN"
Regex(r"(?P<user>[A-Za-z0-9._%+-]+)@(?P<hostname>[A-Za-z0-9.-]+)\.(?P<domain>[A-Za-z]{2,4})") шаблон e-mail (используются именованные регулярные выражения для выделения составляющих: user, hostname и domain
Word( nums ) + Optional( Word(alphas), default = 'AAА' ) слово, состоящее из цифр и букв (например '123ABC'); если исходный текст состоит только из одних цифр, например '123', то будет возвращена строка с значением по умолчанию: " ['123', 'AAA'] "

[править] Грамматика CLData-файла

Ниже приведен пример описания 3-х функций. В действительности их больше сотни, поэтому написать весь перечень по образцу будет несложно.


[править] Анализ результатов

Собственно приведенный выше листинг программы бесполезен, поскольку результатом его работы будет список с постоянно изменяющимся количеством элементов. Идентификация значений этого списка в принципе возможна, но этот процесс будет достаточно утомительным. Поэтому желательно на этапе формирования шаблона присвоить токенам имена.

Для этих целей служить функция setResultsName, которая может быть применена как к отдельным токенам, так и к сгруппированным функцией Group.


Через несколько секунд (к слову сказать, библиотека pyparsing работает достаточно медленно) на экране получим следующий результат:


[править] Дополнительная информация

[править] Примечания

  1. http://wwwiutp.univ-poitiers.fr/COURS-DOCS/docu/NormesClfile/NormesClfile.pdf
Источник — «http://2.xgu.ru/wiki/pyparsing»
На других языках