为什么打印字符会在python代码中消失?

2024-06-16 17:12:10 发布

您现在位置:Python中文网/ 问答频道 /正文

(这个问题源于试图绕过this problem

我正在尝试用python打印一个字典列表。 因为我找不到一个真正的函数可以把python对象转换成字符串(不,json.dumps文件不起作用),我想写一个简单的打印脚本。在

不幸的是,一行开头的字符就消失了。。。 现在,我可能不是python的专家,但是这种行为在我看来是无稽之谈。在

# The out object is returned by a library (rekall) 
# and it is a list of dictionaries.
import rekall
out = rekall.a_modified_module.calculate()

print '[',
for ps in out:
    first = True
    print '{',
    for info in ps:
        if first:
            first = False
        else:
            print '\'%s\':\'%s\',' % (info, ps[info]),
    print '}',
print ']'

我希望输出是:

^{pr2}$

我得到的是:

'pid':'2040', 'name':'leon.exe', 'offset':'2234185984',}]

你能解释一下这里发生了什么事吗?(我跳过循环中的第一行,因为它包含另一个字典,并且输出变得更加疯狂,输出的部分混合在一起)

注:如果您有一个有效的选项来打印一个通用的python对象(类似于JSON.stringify在javascript中,但不必处理JSON对象)请告诉我。在

编辑:我的问题旨在解释(对我来说)这种奇怪的行为, 其中输出取决于括号后打印的内容。 事实上,如果我删除了内部for循环(“for info In ps”),则初始方括号将正确打印。 另外,如果我创建一个管道来将输出发送到另一个程序,则该程序将从括号开始正确地接收输出。在

编辑:为了帮助理解问题的本质和“out”对象的类型,以下是使用“pprint”模块的输出:

[{'name':  [String:ImageFileName]: 'leon.exe\x00',
  'offset': 2236079360,
  'pid':  [unsigned int:UniqueProcessId]: 0x000007FC,
  'psscan': {'CSRSS': False,
             'Handles': False,
             'PsActiveProcessHead': True,
             'PspCidTable': True,
             'Sessions': True}}]

Tags: 对象nameininfofalsetruefor字典
1条回答
网友
1楼 · 发布于 2024-06-16 17:12:10

Python对象有两种方法可用于快速获得其数据的可读表示形式:str提供对象的可打印表示形式,{a2}尝试给出可用于重建对象的字符串:对于许多类型,此函数尝试返回一个字符串,该字符串将在传递给eval()时生成具有相同值的对象。重在“尝试”。类可以自由地用它们自己的__str____repr__方法覆盖默认实现。在

示例输出:

'name':  [String:ImageFileName]: 'leon.exe\x00'

很有趣。它表明rekall模块重写了__repr__,以提供其数据类型([String:ImageFileName]:)的更复杂视图。只是python的实现者给出了更有效的类型描述。它还显示它的字符串'leon.exe\x00'中有不可打印的字符。这意味着,在这个实例中,当打印数据的字符串值时,会发出一个NUL \x00。我会称之为bug,但可能是该模块应该发出原始二进制数据。在

控制台可能会使用不可打印字符进行格式化。例如,\r(回车符)告诉控制台在行的开头重新定位并覆盖字符

^{pr2}$

在我的控制台上,这个逃逸序列

>>> print '\x1b[0;31;40m hello'
hello

把“你好”印成红色。在

如果rekall正在输出原始二进制数据,则您尝试打印的字符串包含不可打印的字符,这些字符会扰乱您的控制台显示。为了使事情变得复杂,rekall模块可能会检查它的stdout是否是一个终端,并更改其输出以向其字符串添加花哨的面向终端的格式。在

假设rekall正在将原始二进制数据放入字符串中,您可以执行str来删除rekall元数据,然后{}来避开麻烦的字符

def mystr(s):
    return repr(str(s))

for ps in out:
    first = True
    for info in ps:
        if first:
            first = False
        else:
            print '\'%s\':\'%s\'' % (mystr(info), mystr(ps[info])))

或者编写你自己的函数来过滤掉你不想要的字符。这在Unicode中有点困难,但是对于ascii文本,我们可以从string.printable中找到一部分字符。在

printable = set(
    '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$'
    '%&\\\'()*+,-./:;<=>?@[\\]^_`{|}~ \t')

def mystr(s):
    return ''.join(filter(printable.__contains__, str(s)))

for ps in out:
    first = True
    for info in ps:
        if first:
            first = False
        else:
            print '\'%s\':\'%s\'' % (mystr(info), mystr(ps[info])))

相关问题 更多 >