ti-enxame.com

Teste de uma string python é imprimível

Eu tenho um código que puxa dados de uma porta COM e eu quero ter certeza de que o que eu tenho realmente é uma string imprimível (ou seja, ASCII, talvez UTF-8) antes de imprimi-lo. Existe uma função para fazer isso? A primeira meia dúzia de lugares que eu olhei, não tem nada que se pareça com o que eu quero. ( cadeia tem printable mas eu não vi nada (lá, ou em os métodos de string ) para verificar se cada caractere em uma string está em outro.

Nota: os caracteres de controle são não imprimíveis para os meus propósitos.


Edit: Eu estava/estou procurando uma única função, não uma solução roll-your-own:

O que acabei com é:

all(ord(c) < 127 and c in string.printable for c in input_str)
24
BCS

Como você disse, o módulo string TEM printable então é apenas um caso de verificar se todos os caracteres em sua string estão em printable:

>>> hello = 'Hello World!'
>>> bell = chr(7)
>>> import string
>>> all(c in string.printable for c in hello)
True
>>> all(c in string.printable for c in bell)
False

Você poderia converter ambas as strings em conjuntos - então o conjunto conteria cada caractere na string uma vez - e verificar se o conjunto criado pela sua string é um subconjunto de os caracteres imprimíveis:

>>> printset = set(string.printable)
>>> helloset = set(hello)
>>> bellset = set(bell)
>>> helloset
set(['!', ' ', 'e', 'd', 'H', 'l', 'o', 'r', 'W'])
>>> helloset.issubset(printset)
True
>>> set(bell).issubset(printset)
False

Então, em resumo, você provavelmente desejaria fazer isso:

import string
printset = set(string.printable)
isprintable = set(yourstring).issubset(printset)
42
Dave Webb

try/except parece ser a melhor maneira:

def isprintable(s, codec='utf8'):
    try: s.decode(codec)
    except UnicodeDecodeError: return False
    else: return True

Eu não confiaria em string.printable, que poderia considerar caracteres de controle "não imprimíveis" que normalmente podem ser "impressos" para fins de controle de terminal (por exemplo, em sequências de escape ANSI de "colorização", se seu terminal for compatível com ANSI). Mas isso, claro, depende dos seus propósitos exatos para querer checar isso!

6
Alex Martelli
>>> # Printable
>>> s = 'test'
>>> len(s)+2 == len(repr(s))
True

>>> # Unprintable
>>> s = 'test\x00'
>>> len(s)+2 == len(repr(s))
False
5
JohnMudd

Esta string do Python 3 contém todos os tipos de caracteres especiais:

s = 'abcd\x65\x66 äüöë\xf1 \u00a0\u00a1\u00a2 漢字 \a\b\r\t\n\v\\ \231\x9a \u2640\u2642\uffff'

Se você tentar mostrá-lo no console (ou usar repr), ele fará um bom trabalho ao escapar de todos os caracteres não imprimíveis da string:

>>> s
'abcdef äüöëñ \xa0¡¢ 漢字 \x07\x08\r\t\n\x0b\\ \x99\x9a ♀♂\uffff'

É inteligente o suficiente para reconhecer, e. guia horizontal (\t) como imprimível, mas guia vertical (\v) como não imprimível (aparece como \x0b em vez de \v).

Todos os outros caracteres não imprimíveis também aparecem como \xNN ou \uNNNN na repr. Portanto, podemos usar isso como o teste:

def is_printable(s):
    return not any(repr(ch).startswith("'\\x") or repr(ch).startswith("'\\u") for ch in s)

Pode haver alguns caracteres limítrofes, por exemplo, espaço em branco sem quebra (\xa0) é tratado como não imprimível aqui. Talvez não devesse ser, mas aquelas especiais poderiam então ser codificadas.


P.S.

Você pode fazer isso para extrair apenas caracteres imprimíveis de uma string:

>>> ''.join(ch for ch in s if is_printable(ch))
'abcdef äüöëñ ¡¢ 漢字 \r\t\n\\  ♀♂'
3
zvone

O meu é uma solução para se livrar de qualquer conjunto conhecido de caracteres. isso pode ajudar.

non_printable_chars = set("\n\t\r ")     # Space included intensionally
is_printable = lambda string:bool(set(string) - set(non_printable_chars))
...
...
if is_printable(string):
    print("""do something""")

...

0
Jerin K. John

A função category do unicodedatamodule pode atender às suas necessidades. Por exemplo, você pode usar isso para verificar se há algum caractere de controle em uma string enquanto ainda permite caracteres não-ASCII.

>>> import unicodedata

>>> def has_control_chars(s):
...     return any(unicodedata.category(c) == 'Cc' for c in s)

>>> has_control_chars('Hello 世界')
False

>>> has_control_chars('Hello \x1f 世界')
True
0
gatkin