Показывать непечатаемые символы в строке
Возможно ли визуализировать непечатаемые символы в строке python с шестнадцатеричными значениями?
например. Если у меня есть строка с новой строкой внутри, я хотел бы заменить ее на \x0a
.
Я знаю, что есть repr()
, который даст мне... \n
, но я ищу шестнадцатеричную версию.
Ответы
Ответ 1
Вам нужно будет сделать перевод вручную; например, пропустите строку с регулярным выражением и замените каждое вхождение шестнадцатеричным эквивалентом.
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
Ответ 2
Я не знаю какого-либо встроенного метода, но это довольно легко сделать с помощью понимания:
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)
Ответ 3
Я опаздываю на вечеринку, но если вам это нужно для простой отладки, я обнаружил, что это работает:
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,']
Ужасно, но это помогло мне найти непечатаемые символы в строке.
Ответ 4
Изменение решения 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-функции, о которых я знаю, эти специальные последовательности вместо их шестнадцатеричных версий.
Ответ 5
Я сделал что-то подобное однажды, получив подкласс 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')))
Ответ 6
Существует также способ печати непечатных символов в том смысле, что они выполняются как команды внутри строки, даже если они не видимы (прозрачны) в строке, и их присутствие можно наблюдать, измеряя длину строки с помощью len
а также просто поместив курсор мыши в начало строки и посмотрев/посчитав, сколько раз вам нужно нажать клавишу со стрелкой, чтобы перейти от начала к концу, как это ни странно, некоторые отдельные символы могут иметь длину, например, 3, что кажется озадачивающим. (Не уверен, что это уже было продемонстрировано в предыдущих ответах)
В приведенном ниже снимке экрана, приведенном ниже, я вставил 135-битную строку, которая имеет определенную структуру и формат (которую я должен был предварительно создать вручную для определенных позиций бит и ее общей длины), чтобы она интерпретировалась ascii конкретной программой я ' и в полученной напечатанной строке находятся непечатаемые символы, такие как "разрыв строки", который буквально вызывает разрыв строки (исправление: подача формы, новая страница, которую я имел в виду, а не разрыв строки) в в выводе на печать есть дополнительная целая пустая строка между напечатанным результатом (см. ниже):
Пример печати непечатаемых символов, которые появляются в напечатанной строке
Input a string:100100001010000000111000101000101000111011001110001000100001100010111010010101101011100001011000111011001000101001000010011101001000000
HPQGg]+\,vE!:@
>>> len('HPQGg]+\,vE!:@')
17
>>>
В приведенном выше фрагменте кода попробуйте скопировать и вставить строку HPQGg]+\,vE!:@
прямо с этого сайта и посмотреть, что произойдет, когда вы вставите ее в Python IDLE.
Подсказка: Вы должны нажать на стрелку/курсор три раза, чтобы пролистать две буквы от P
до Q
, даже если они появляются рядом друг с другом, так как на самом деле между ними есть команда File Separator
ascii. их.
Однако, несмотря на то, что мы получаем то же начальное значение при декодировании его в виде байтового массива в шестнадцатеричный формат, если мы преобразуем этот шестнадцатеричный код обратно в байты, они выглядят по-разному (возможно, нехватка кодирования, не уверен), но в любом случае вышеприведенный вывод программы печатает непечатаемые символы (я случайно наткнулся на это, пытаясь разработать метод сжатия/эксперимент).
>>> bytes(b'HPQGg]+\,vE!:@').hex()
'48501c514767110c5d2b5c2c7645213a40'
>>> bytes.fromhex('48501c514767110c5d2b5c2c7645213a40')
b'HP\x1cQGg\x11\x0c]+\\,vE!:@'
>>> (0x48501c514767110c5d2b5c2c7645213a40 == 0b100100001010000000111000101000101000111011001110001000100001100010111010010101101011100001011000111011001000101001000010011101001000000)
True
>>>
В приведенной выше 135-битной строке первые 16 групп по 8 бит со стороны с прямым порядком байтов кодируют каждый символ (включая непечатаемый), тогда как последняя группа из 7 бит приводит к символу @
, как видно ниже:
Техническая разбивка формата вышеуказанной 135-битной строки
А здесь в качестве текста разбивка 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
команда).