Показывать непечатаемые символы в строке

можно ли визуализировать непечатаемые символы в строке python с его шестнадцатеричными значениями?

например, если у меня есть строка с новой строкой внутри, я хотел бы заменить ее на x0a.

Я знаю, что есть repr() что даст мне ...n, но я ищу версию hex.

5 ответов


вам придется сделать перевод вручную; пройдите через строку с регулярным выражением, например, и замените каждое вхождение шестнадцатеричным эквивалентом.

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)

приведенный выше пример соответствует только новым строкам и возвратам каретки, но вы можете развернуть, какие символы совпадают, включая использование \x escape-коды и диапазоны.

>>> 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

Я не знаю никакого встроенного метода, но это довольно легко сделать, используя понимание:

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)

Я немного опоздала на вечеринку, но если вам это нужно для простой отладки, я обнаружил, что это работает:

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

procd = [c for c in string]

print(procd)

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

некрасиво, но это помогло мне найти непечатные символы в строке.


изменение решения 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)

конечно, если str.isprintable - это не совсем то определение, которые вы хотите, вы можете написать другую функцию. (Обратите внимание, что это очень отличается от того, что в string.printable - помимо обработки не-ASCII печатных и непечатаемых символов, он также рассматривает \n, \r, \t, \x0b и \x0c как непечатные.

вы можете сделайте это более компактным; это явно, чтобы показать все шаги, связанные с обработкой строк Unicode. Например:

def escape(c):
    if c.printable():
        return c
    elif c <= '\xff':
        return r'\x{0:02x}'.format(ord(c))
    else:
        return c.encode('unicode_escape').decode('ascii')

действительно, независимо от того, что вы делаете, вам придется справиться \r, \n и \t явно, потому что все встроенные и stdlib функции, о которых я знаю, будут избегать их через эти специальные последовательности вместо их шестнадцатеричных версий.


Я сделал что-то похожее на наследование str подкласс с пользовательским __repr__() метод, который сделал то, что хотел. Это не совсем то, что вы ищете, но может дать вам некоторые идеи.

# -*- 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')))