【问题标题】:How to parse Python code while keeping string literals exactly as-is?如何在保持字符串文字原样的同时解析 Python 代码?
【发布时间】:2019-05-28 04:35:35
【问题描述】:

我正在尝试遍历 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 源代码的同时保持原始文字与所写的完全一致?

有内置的方法吗?

【问题讨论】:

  • 根据u 前缀在 Python 3 下实现的方式,如PEP-0414 中所述,内部表示实际上没有任何变化,因此无论是否包含原始语法,您想要什么u 与否,不会从ast api 表达或传达出去。
  • @metatoaster:是的,但是有不同的 API 吗?还是人们为此编写自己的词法分析器/解析器?

标签: python parsing abstract-syntax-tree literals string-length


【解决方案1】:

您要查找的信息不是 AST 级别的信息。检查此类内容的适当级别是令牌级别,您可以为此使用tokenize 模块。

tokenize API 很尴尬——它需要一个行为类似于二进制文件对象的readline 方法的输入——所以你需要以二进制模式打开文件,如果你有一个字符串,您需要使用encodeio.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)

【讨论】:

  • 哇,谢谢!我已经彻底放弃了希望!对于其他尝试解析字符串文字的人,请尝试 Python 3 中的 list(tokenize.tokenize(io.BytesIO(b'\'x\'; u\'x\'; b\'x\'; "x"; u"x"; b"x"').readline)) 或 Python 2 中的 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)([]))
  • @Mehrdad:对于 Python 2,您应该使用 tokenize.generate_tokens 而不是 tokenize.tokenize。他们在 Python 3 中重命名了函数。(另外,Python 2 提供常规元组而不是命名元组,因此您必须按位置访问元素。)
  • 是的,我在几秒钟前才注意到 :) 谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-10-22
  • 2013-06-22
  • 2021-05-21
  • 1970-01-01
  • 2018-12-21
  • 1970-01-01
相关资源
最近更新 更多