Я пытаюсь просмотреть все строковые литералы в исходном коде Python, в то же время имея возможность определить, какой строковый литерал каждый из них.
К сожалению, как вы можете видеть в этом примере, ast.parse
не работает:
[node.value.s for node in ast.parse('\'x\'; u\'x\'; b\'x\'; "x"; u"x"; b"x"').body]
Результат:
['x', 'x', b'x', 'x', 'x', b'x']
это означает, что я не могу различить литералы ''
и u''
или ''
и ""
и т. д.
Как я могу разобрать исходный код Python, сохраняя при этом исходный литерал точно таким, как он написан?
Есть встроенный способ?
@metatoaster: Да, но есть ли другой API? Или для этого люди пишут свои лексеры/парсеры?
Информация, которую вы ищете, не является информацией уровня AST. Подходящим уровнем для проверки подобных вещей является уровень токена, и вы можете использовать для этого модуль tokenize
.
API tokenize
довольно неудобен — ему нужен ввод, который ведет себя как метод readline
двоичного файлового объекта, поэтому вам нужно открывать файлы в двоичном режиме, и если у вас есть строка, вам нужно будет использовать encode
и io.BytesIO
для конвертации.
import tokenize
token_stream = tokenize.tokenize(input_file.readline)
for token in token_stream:
if token.type == tokenize.STRING:
do_whatever_with(token.string)
Вот версия Python 2 — имена функций другие, и вам нужно обращаться к информации о токенах позиционно, потому что вы получаете обычные кортежи вместо именованных кортежей:
import tokenize
token_stream = tokenize.generate_tokens(input_file.readline)
for token_type, token_string, _, _, _ in token_stream:
if token_type == tokenize.STRING:
do_whatever_with(token_string)
Вау спасибо!! Я совсем потерял надежду! Для тех, кто еще пытается разобрать строковый литерал, попробуйте list(tokenize.tokenize(io.BytesIO(b'\'x\'; u\'x\'; b\'x\'; "x"; u"x"; b"x"').readline))
в Python 3 или list((lambda items: tokenize.tokenize(io.BytesIO(b'\'x\'; u\'x\'; b\'x\'; "x"; u"x"; b"x"').readline, lambda *args: items.append(args)) and None or items)([]))
в Python 2.
@Mehrdad: для Python 2 вы должны использовать tokenize.generate_tokens
вместо tokenize.tokenize
. Они переименовали функции в Python 3. (Кроме того, Python 2 предоставляет обычные кортежи вместо именованных кортежей, поэтому вам нужно обращаться к элементам позиционно.)
Да, я только что заметил это несколько секунд назад :) спасибо!
В соответствии с тем, как этот префикс
u
реализован в Python 3, как указано в ПЭП-0414, фактически нет никаких изменений во внутреннем представлении, поэтому то, что вы хотите, независимо от того, включал ли исходный синтаксисu
или нет, не будет выражено или передано выйти изast
API.