Документация Python неофициальный перевод
Содержание страницы

24.3. shlex – Простой лексический анализshlex – Simple lexical analysis

Исходный код: Lib/shlex.py


Класс shlex упрощает написание лексических анализаторов для синтаксиса, напоминающего синтаксис оболочки Unix. Это часто бывает полезно для создания мини-языков (например, в конфигурационных файлах приложений Python) или для разбора строк в кавычках.

Модуль shlex определяет следующие функции:

shlex.split(s, comments=False, posix=True)

Разделяет строку s, используя синтаксис, подобный оболочке. Если comments равно False (по умолчанию), разбор комментариев в заданной строке будет отключён (устанавливает атрибут commenters экземпляра shlex в пустую строку). Эта функция работает в режиме POSIX по умолчанию, но использует не-POSIX режим, если аргумент posix равен False.

Примечание

Поскольку функция split() создаёт экземпляр shlex , передача None в качестве s будет читать строку для разбиения из стандартного ввода.

shlex.quote(s)

Возвращает экранированную для оболочки версию строки s. Возвращаемое значение – это строка, которую можно безопасно использовать как один токен в командной строке оболочки в тех случаях, когда нельзя использовать список.

Этот подход был бы небезопасен:

>>> filename = 'somefile; rm -rf ~'
>>> command = 'ls -l {}'.format(filename)
>>> print(command)  # выполнено оболочкой: бабах!
ls -l somefile; rm -rf ~

quote() позволяет закрыть брешь в безопасности:

>>> command = 'ls -l {}'.format(quote(filename))
>>> print(command)
ls -l 'somefile; rm -rf ~'
>>> remote_command = 'ssh home {}'.format(quote(command))
>>> print(remote_command)
ssh home 'ls -l '"'"'somefile; rm -rf ~'"'"''

Экранирование совместимо с оболочками UNIX и с split():

>>> remote_command = split(remote_command)
>>> remote_command
['ssh', 'home', "ls -l 'somefile; rm -rf ~'"]
>>> command = split(remote_command[-1])
>>> command
['ls', '-l', 'somefile; rm -rf ~']

Новое в версии 3.3.

Модуль shlex определяет следующий класс:

class shlex.shlex(instream=None, infile=None, posix=False)

Экземпляр shlex или его подкласса является объектом лексического анализатора. Аргумент инициализации, если он указан, определяет источник символов. Это должен быть файло- или потокоподобный объект с методами read() и readline(), либо строка. Если аргумент не задан, ввод берётся из sys.stdin. Второй необязательный аргумент – строка имени файла, которая задаёт начальное значение атрибута infile. Если аргумент instream опущен или равен sys.stdin, этот второй аргумент по умолчанию принимает значение "stdin". Аргумент posix определяет режим работы: когда posix не является истинным (по умолчанию), экземпляр shlex работает в режиме совместимости. При работе в режиме POSIX shlex старается максимально точно соблюдать правила синтаксического анализа оболочки POSIX.

См. также

Модуль configparser
Синтаксический анализатор конфигурационных файлов, аналогичных файлам .ini в Windows.

24.3.1. Объекты shlexshlex Objects

Экземпляр shlex имеет следующие методы:

shlex.get_token()

Возвращает токен. Если токены были помещены в стек с помощью push_token(), извлекает токен из стека. В противном случае читает один токен из входного потока. Если при чтении сразу встречается конец файла, возвращается eof (пустая строка ('') в не-POSIX режиме и None в режиме POSIX).

shlex.push_token(str)

Помещает аргумент в стек токенов.

shlex.read_token()

Читает сырой токен. Игнорирует стек возврата и не интерпретирует запросы источника. (Обычно это не является полезной точкой входа и документируется здесь только для полноты.)

shlex.sourcehook(filename)

Когда shlex обнаруживает запрос источника (см. source ниже), этому методу передаётся следующий токен в качестве аргумента, и ожидается, что он вернёт кортеж, состоящий из имени файла и открытого файлоподобного объекта.

Обычно этот метод сначала удаляет кавычки из аргумента. Если результат – абсолютный путь, или нет активного предыдущего запроса источника, или предыдущий источник был потоком данных (например, sys.stdin), результат остаётся без изменений. В противном случае, если результат – относительный путь, к нему добавляется часть пути каталога файла, находящегося непосредственно перед ним в стеке включения источников (такое поведение аналогично тому, как препроцессор C обрабатывает #include "file.h").

Результат этих действий трактуется как имя файла и возвращается в качестве первого компонента кортежа, а к нему применяется open() для получения второго компонента. (Примечание: это обратный порядок аргументов при инициализации экземпляра!)

Этот хук предоставляется, чтобы вы могли использовать его для реализации путей поиска по каталогам, добавления расширений файлов и других трюков с пространствами имён. Соответствующего хука «закрытия» нет, но экземпляр shlex вызовет метод close() входного потока источника, когда тот вернёт EOF.

Для более явного управления стеком источников используйте методы push_source() и pop_source().

shlex.push_source(newstream, newfile=None)

Помещает поток входного источника в стек ввода. Если указан аргумент filename, он будет доступен позже для использования в сообщениях об ошибках. Это тот же метод, который внутренне используется методом sourcehook().

shlex.pop_source()

Извлекает последний помещённый входной источник из стека ввода. Это тот же метод, который используется внутри, когда лексер достигает EOF для помещённого в стек входного потока.

shlex.error_leader(infile=None, lineno=None)

Этот метод формирует префикс сообщения об ошибке в формате метки ошибок компилятора C в Unix; формат – '"%s", line %d: ', где %s заменяется на имя текущего исходного файла, а %d – на номер текущей строки ввода (необязательные аргументы позволяют переопределить эти значения).

Это удобство предоставляется для того, чтобы побудить пользователей shlex генерировать сообщения об ошибках в стандартном, анализируемом формате, который понимают Emacs и другие инструменты Unix.

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

shlex.commenters

Строка символов, которые распознаются как начало комментария. Все символы от начала комментария до конца строки игнорируются. По умолчанию включает только '#'.

shlex.wordchars

Строка символов, которые будут накапливаться в составные токены. По умолчанию включает все буквы и цифры ASCII и символ подчёркивания.

shlex.whitespace

Символы, которые считаются пробельными и пропускаются. Пробельные символы разделяют токены. По умолчанию включает пробел, табуляцию, перевод строки и возврат каретки.

shlex.escape

Символы, которые будут считаться экранирующими. Это используется только в режиме POSIX и по умолчанию включает только '\'.

shlex.quotes

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

shlex.escapedquotes

Символы в quotes, которые будут интерпретировать экранирующие символы, определённые в escape. Это используется только в режиме POSIX и по умолчанию включает только '"'.

shlex.whitespace_split

Если True, токены будут разделяться только по пробельным символам. Это полезно, например, для разбора командных строк с помощью shlex, получая токены аналогично аргументам оболочки.

shlex.infile

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

shlex.instream

Входной поток, из которого данный экземпляр shlex читает символы.

shlex.source

По умолчанию этот атрибут равен None. Если присвоить ему строку, эта строка будет распознаваться как запрос включения на лексическом уровне, аналогично ключевому слову source в различных оболочках. То есть следующий непосредственно токен будет открыт как имя файла, и ввод будет поступать из этого потока до достижения конца файла; после этого будет вызван метод close() этого потока, и источником ввода снова станет исходный входной поток. Запросы источника могут быть вложенными на любое количество уровней.

shlex.debug

Если этот атрибут является числовым и равен 1 или больше, экземпляр shlex будет выводить подробную информацию о своих действиях. Если потребуется этим воспользоваться, можно изучить исходный код модуля, чтобы узнать подробности.

shlex.lineno

Номер строки в исходном файле (количество встреченных символов новой строки плюс один).

shlex.token

Буфер токенов. Его может быть полезно проверить при перехвате исключений.

shlex.eof

Токен, используемый для определения конца файла. В не-POSIX-режиме он устанавливается в пустую строку (''), а в POSIX-режиме – в None.

24.3.2. Правила синтаксического анализаParsing Rules

При работе в не-POSIX режиме shlex будет следовать следующим правилам.

  • Символы кавычек не распознаются внутри слов (Do"Not"Separate разбирается как одно слово Do"Not"Separate);
  • Символы экранирования не распознаются;
  • Заключение символов в кавычки сохраняет буквальное значение всех символов внутри кавычек;
  • Закрывающие кавычки разделяют слова ("Do"Separate разбирается как "Do" и Separate);
  • Если значение whitespace_split равно False, любой символ, не объявленный как символ слова, пробел или кавычка, будет возвращён как односимвольный токен. Если оно равно True, shlex будет разделять слова только по пробельным символам;
  • EOF обозначается пустой строкой ('');
  • Невозможно разобрать пустые строки, даже если они в кавычках.

При работе в POSIX режиме shlex будет следовать следующим правилам разбора.

  • Кавычки удаляются и не разделяют слова ("Do"Not"Separate" разбирается как одно слово DoNotSeparate);
  • Неэкранированные (не в кавычках) escape-символы (например, '\') сохраняют буквальное значение следующего за ними символа;
  • Заключение символов в кавычки, не входящие в escapedquotes (например, "'"), сохраняет буквальное значение всех символов внутри кавычек;
  • Заключение символов в кавычки, которые являются частью escapedquotes (например, '"'), сохраняет буквальное значение всех символов внутри кавычек, за исключением символов, упомянутых в escape. Escape-символы сохраняют своё особое значение только в том случае, если за ними следует используемая кавычка или сам escape-символ. В противном случае escape-символ считается обычным символом.
  • EOF обозначается значением None;
  • Пустые строки в кавычках ('') допускаются.