Afficher les caractères non imprimables dans une chaîne de caractères

est-il possible de visualiser des caractères non imprimables dans une chaîne python avec ses valeurs hex?

par exemple Si j'ai une chaîne avec un saut de ligne à l'intérieur, je voudrais la remplacer par x0a.

je sais qu'il est repr() ce qui me donnera ...<!-Mais je cherche la version hexadécimale.

10
demandé sur Martijn Pieters 2012-12-18 11:00:13

5 réponses

vous devrez faire la traduction manuellement, passer par la chaîne de caractères avec une expression régulière par exemple, et remplacer chaque occurrence par l'équivalent hexadécimal.

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)

L'exemple ci-dessus ne correspond qu'à des lignes et des retours de chariot, mais vous pouvez étendre quels caractères sont appariés, y compris en utilisant \x codes et portées d'évacuation.

>>> 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
4
répondu Martijn Pieters 2012-12-18 07:17:07

je ne sais pas du tout intégré dans la méthode, mais il est assez facile de le faire à l'aide d'une compréhension:

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)
11
répondu ecatmur 2012-12-18 14:55:15

je suis un peu en retard à la fête, mais si vous en avez besoin pour un débogage simple, j'ai trouvé que cela fonctionne:

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,']

laid, mais ça m'a aidé à trouver des caractères non imprimables dans une chaîne.

7
répondu Carcigenicate 2015-03-01 00:58:17

modifier la solution d'ecatmur pour traiter les caractères non-imprimables non-ASCII la rend moins triviale et plus odieuse:

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)

bien sûr, si str.isprintable n'est pas exactement la définition que vous voulez, vous pouvez écrire une fonction différente. (Notez que c'est un ensemble très différent de ce qui est dans string.printable-en plus de traiter les caractères non-ASCII imprimables et non-imprimables, il considère aussi \n,\r,\t,\x0b et \x0c comme non-imprimable.

Vous pouvez rendre cela plus compact; ceci est explicite juste pour montrer toutes les étapes impliquées dans la manipulation des chaînes Unicode. Par exemple:

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

Vraiment, peu importe ce que vous faites, vous allez avoir à gérer \r,\n et \t explicitement, parce que toutes les fonctions intégrées et stdlib que je connais leur échapperont via ces séquences spéciales au lieu de leurs versions hex.

1
répondu abarnert 2012-12-18 21:56:15

j'ai fait quelque chose de similaire une fois en dérivant une str sous-classe avec un custom __repr__() méthode qui a fait ce que je voulais. Ce n'est pas exactement ce que vous cherchez, mais peut vous donner quelques idées.

# -*- 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')))
0
répondu martineau 2012-12-18 12:24:51