Python 在字符串中显示不可打印的字符

Python 在字符串中显示不可打印的字符,python,python-3.x,escaping,Python,Python 3.x,Escaping,是否可以将python字符串中不可打印的字符及其十六进制值可视化 e、 g.如果我有一个内有换行符的字符串,我想用\x0a替换它 我知道有repr()可以给我…\n,但我正在寻找十六进制版本。您必须手动进行翻译;例如,使用正则表达式遍历字符串,并用十六进制等价项替换每个匹配项 import re replchars = re.compile(r'[\n\r]') def replchars_to_hex(match): return r'\x{0:02x}'.format(ord(ma

是否可以将python字符串中不可打印的字符及其十六进制值可视化

e、 g.如果我有一个内有换行符的字符串,我想用
\x0a
替换它


我知道有
repr()
可以给我…
\n
,但我正在寻找十六进制版本。

您必须手动进行翻译;例如,使用正则表达式遍历字符串,并用十六进制等价项替换每个匹配项

import re

replchars = re.compile(r'[\n\r]')
def replchars_to_hex(match):
    return r'\x{0:02x}'.format(ord(match.group()))

replchars.sub(replchars_to_hex, inputtext)
上面的示例仅匹配换行符和回车符,但您可以扩展匹配的字符,包括使用转义码和范围

>>> inputtext = 'Some example containing a newline.\nRight there.\n'
>>> replchars.sub(replchars_to_hex, inputtext)
'Some example containing a newline.\\x0aRight there.\\x0a'
>>> print(replchars.sub(replchars_to_hex, inputtext))
Some example containing a newline.\x0aRight there.\x0a

我曾经做过类似的事情,用一个自定义的
\uuuu repr\uuu()
方法派生了一个
str
子类,该方法实现了我想要的功能。这不完全是你想要的,但可能会给你一些想法

# -*- coding: iso-8859-1 -*-

# special string subclass to override the default
# representation method. main purpose is to
# prefer using double quotes and avoid hex
# representation on chars with an ord > 128
class MsgStr(str):
    def __repr__(self):
        # use double quotes unless there are more of them within the string than
        # single quotes
        if self.count("'") >= self.count('"'):
            quotechar = '"'
        else:
            quotechar = "'"

        rep = [quotechar]
        for ch in self:
            # control char?
            if ord(ch) < ord(' '):
                # remove the single quotes around the escaped representation
                rep += repr(str(ch)).strip("'")
            # embedded quote matching quotechar being used?
            elif ch == quotechar:
                rep += "\\"
                rep += ch
            # else just use others as they are
            else:
                rep += ch
        rep += quotechar

        return "".join(rep)

if __name__ == "__main__":
    s1 = '\tWürttemberg'
    s2 = MsgStr(s1)
    print "str    s1:", s1
    print "MsgStr s2:", s2
    print "--only the next two should differ--"
    print "repr(s1):", repr(s1), "# uses built-in string 'repr'"
    print "repr(s2):", repr(s2), "# uses custom MsgStr 'repr'"
    print "str(s1):", str(s1)
    print "str(s2):", str(s2)
    print "repr(str(s1)):", repr(str(s1))
    print "repr(str(s2)):", repr(str(s2))
    print "MsgStr(repr(MsgStr('\tWürttemberg'))):", MsgStr(repr(MsgStr('\tWürttemberg')))
#-*-编码:iso-8859-1-*-
#用于覆盖默认值的特殊字符串子类
#表示方法。主要目的是
#喜欢使用双引号,避免使用十六进制
#ord>128的字符上的表示
MsgStr类(str):
定义报告(自我):
#使用双引号,除非字符串中的双引号多于
#单引号
如果self.count(“”>)=self.count(“”):
quotechar=“”
其他:
quotechar=“””
rep=[quotechar]
对于Chin self:
#控制字符?
如果ord(ch)
我不知道有任何内置方法,但使用理解功能很容易做到:

import string
printable = string.ascii_letters + string.digits + string.punctuation + ' '
def hex_escape(s):
    return ''.join(c if c in printable else r'\x{0:02x}'.format(ord(c)) for c in s)

修改ecatmur的解决方案以处理不可打印的非ASCII字符使其变得不那么琐碎,也更令人讨厌:

def escape(c):
    if c.printable():
        return c
    c = ord(c)
    if c <= 0xff:
        return r'\x{0:02x}'.format(c)
    elif c <= '\uffff':
        return r'\u{0:04x}'.format(c)
    else:
        return r'\U{0:08x}'.format(c)

def hex_escape(s):
    return ''.join(escape(c) for c in s)

实际上,无论你做什么,你都必须明确地处理
\r
\n
\t
,因为我知道的所有内置函数和stdlib函数都会通过这些特殊序列而不是十六进制版本来转义它们。

我来晚了,但如果你需要它来进行简单的调试,我发现这是有效的:

string = "\n\t\nHELLO\n\t\n\a\17"

procd = [c for c in string]

print(procd)

# Prints ['\n,', '\t,', '\n,', 'H,', 'E,', 'L,', 'L,', 'O,', '\n,', '\t,', '\n,', '\x07,', '\x0f,']

丑陋,但它帮助我在字符串中找到不可打印的字符。

还有一种方法可以打印不可打印的字符,即它们在字符串中作为命令执行,即使在字符串中不可见(透明),通过使用
len
测量字符串的长度,以及简单地将鼠标光标放在字符串的开头,并查看/计算从开始到结束需要点击箭头键的次数,可以观察到它们的存在,奇怪的是,一些单个字符的长度可能为3,例如,这似乎令人困惑。(不确定之前的回答中是否已经证明了这一点)

在下面的示例屏幕截图中,我粘贴了一个135位字符串,该字符串具有特定的结构和格式(我必须事先手动创建特定的位位置及其总长度),以便我运行的特定程序将其解释为ascii,在生成的打印字符串中有不可打印的字符,例如“换行符”,它会在打印输出中造成换行(更正:换页,我指的是新页,不是换行符),在打印结果之间有一个额外的整行空白(见下文):

在上面的代码摘录中,尝试复制粘贴字符串
HPQGg]+\,vE!:@直接从这个站点开始,看看当您将它粘贴到Python IDLE中时会发生什么

提示:您必须轻按箭头/光标三次,才能跨过从
p
Q
的两个字母,即使它们彼此相邻,因为它们之间实际上有一个
文件分隔符
ascii命令

然而,即使我们在将其作为字节数组解码为十六进制时得到相同的起始值,如果我们将该十六进制转换回字节,它们看起来会有所不同(可能没有编码,不确定),但无论哪种方式,程序的上述输出都会打印不可打印的字符(我在尝试开发压缩方法/实验时偶然发现了这一点)

在上述135位字符串中,大端端的前16组8位对每个字符进行编码(包括不可打印),而最后一组7位产生
@
符号,如下所示:

这里的文本是135位字符串的分解:

10010000 = H (72)
10100000 = P (80)
00111000 = x1c (28 for File Separator) *
10100010 = Q (81)
10001110 = G(71)
11001110 = g (103)
00100010 = x11 (17 for Device Control 1) *
00011000 = x0c (12 for NP form feed, new page) *
10111010 = ] (93 for right bracket ‘]’
01010110 = + (43 for + sign)
10111000 = \ (92 for backslash)
01011000  = , (44 for comma, ‘,’)
11101100  = v (118)
10001010 = E (69)
01000010 = ! (33 for exclamation)
01110100 = : (58  for colon ‘:’)
1000000  =  @ (64 for ‘@’ sign)

因此,在结束时,关于在上面的字节数组中将不可打印内容显示为十六进制的子问题的答案显示为字母
x1c
,这表示文件分隔符命令,提示中也提到了该命令。如果不包括左侧的前缀
b
,则字节数组可以被视为字符串,并且再次显示该值显示在打印字符串中,尽管它是不可见的(尽管可以通过提示和
len
命令观察到它的存在)。

内置编解码器
string\u escape
s.encode('string\u escape')
)a
Input a string:100100001010000000111000101000101000111011001110001000100001100010111010010101101011100001011000111011001000101001000010011101001000000
HPQGg]+\,vE!:@
>>> len('HPQGg]+\,vE!:@')
17
>>>
>>> bytes(b'HPQGg]+\,vE!:@').hex()
'48501c514767110c5d2b5c2c7645213a40'
>>> bytes.fromhex('48501c514767110c5d2b5c2c7645213a40')
b'HP\x1cQGg\x11\x0c]+\\,vE!:@'

>>> (0x48501c514767110c5d2b5c2c7645213a40 == 0b100100001010000000111000101000101000111011001110001000100001100010111010010101101011100001011000111011001000101001000010011101001000000)
True
>>> 
10010000 = H (72)
10100000 = P (80)
00111000 = x1c (28 for File Separator) *
10100010 = Q (81)
10001110 = G(71)
11001110 = g (103)
00100010 = x11 (17 for Device Control 1) *
00011000 = x0c (12 for NP form feed, new page) *
10111010 = ] (93 for right bracket ‘]’
01010110 = + (43 for + sign)
10111000 = \ (92 for backslash)
01011000  = , (44 for comma, ‘,’)
11101100  = v (118)
10001010 = E (69)
01000010 = ! (33 for exclamation)
01110100 = : (58  for colon ‘:’)
1000000  =  @ (64 for ‘@’ sign)