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

时间:2016-10-26 15:27:58

标签: python string object printing

(这个问题源于试图绕过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 ']'

我希望输出为:

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

相反,我得到了这个:

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

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

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

编辑:我的问题旨在解释这种奇怪的(对我来说)行为, 输出取决于括号后打印的内容。 实际上,如果我删除内部for循环(“for ps 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}}]

1 个答案:

答案 0 :(得分:0)

Python对象有两种方法用于获取其数据的快速人类可读表示:str,它为提供了一个可以打印的对象的可打印表示repr提供一个可用于重建对象的字符串:对于许多类型,此函数尝试返回一个字符串,该字符串在传递给eval()时会产生具有相同值的对象。沉重的重要事件"尝试"。使用自己的__str____repr__方法,类可以自由覆盖默认实现。

您的示例输出:

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

很有意思。它显示rekall模块覆盖__repr__以提供其数据类型([String:ImageFileName]:)的更复杂视图。但这不是有效的python - 实现者只是给出了更有类型的描述。它还显示其字符串'leon.exe\x00'中包含不可打印的字符。这意味着,在这种情况下,在打印数据的字符串值时会发出NUL \x00。我会称这是一个错误 - 但可能是该模块应该发出原始二进制数据。

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

>>> print 'foo\rbar'
bar

在我的控制台上,这个转义序列

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

制作"你好"用红色打印。

如果rekall正在输出原始二进制数据,那么您尝试打印的字符串将具有不可打印的字符,从而弄乱您的控制台显示。为了使事情变得复杂,rekall模块可能正在检查其stdout是否是终端并更改其输出以向其字符串添加花哨的面向终端的格式。

假设rekall将原始二进制数据放入字符串中,您可以str删除rekall元数据,然后repr以逃避麻烦的字符

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])))
相关问题