Às vezes, quando recebo a entrada de um arquivo ou do usuário, recebo uma string com sequências de escape. Gostaria de processar as sequências de escape da mesma forma que o Python processa as sequências de escape em literais de string .
Por exemplo, digamos que myString
seja definido como:
>>> myString = "spam\\neggs"
>>> print(myString)
spam\neggs
Quero uma função (vou chamá-la process
) que faça isso:
>>> print(process(myString))
spam
eggs
É importante que a função possa processar todas as sequências de escape em Python (listadas em uma tabela no link acima).
O Python tem uma função para fazer isso?
'spam'+"eggs"+'''some'''+"""more"""
seja processada?myString = "'spam'+\"eggs\"+'''some'''+\"\"\"more\"\"\""
,print(bytes(myString, "utf-8").decode("unicode_escape"))
parece funcionar.Respostas:
A coisa correta a fazer é usar o código 'string-escape' para decodificar a string.
Não use o AST ou eval. Usar os codecs de string é muito mais seguro.
fonte
'string\W+escape'
Notice that spelling alternatives that only differ in case or use a hyphen instead of an underscore are also valid aliases; therefore, e.g. 'utf-8' is a valid alias for the 'utf_8' codec.
>>> print("juancarlo\\tañez".encode('utf-8').decode('unicode_escape'))
Você obtém:juancarlo añez
latin1
é assumido porunicode_escape
, refaça o bit de codificação / decodificação, por exemplos.encode('utf-8').decode('unicode_escape').encode('latin1').decode('utf8')
unicode_escape
não funciona em geralAcontece que a solução
string_escape
ouunicode_escape
não funciona em geral - particularmente, não funciona na presença de Unicode real.Se você puder ter certeza de que todos os caracteres não ASCII terão escape (e lembre-se, qualquer coisa além dos primeiros 128 caracteres não são ASCII),
unicode_escape
fará a coisa certa para você. Mas se já houver caracteres não-ASCII literais em sua string, as coisas darão errado.unicode_escape
é fundamentalmente projetado para converter bytes em texto Unicode. Mas em muitos lugares - por exemplo, código-fonte Python - os dados-fonte já são texto Unicode.A única maneira de funcionar corretamente é codificar o texto em bytes primeiro. UTF-8 é a codificação sensata para todo o texto, então deve funcionar, certo?
Os exemplos a seguir estão em Python 3, de modo que os literais de string são mais limpos, mas o mesmo problema existe com manifestações ligeiramente diferentes em Python 2 e 3.
Bem, isso está errado.
A nova maneira recomendada de usar codecs que decodificam texto em texto é chamar
codecs.decode
diretamente. Isso ajuda?De modo nenhum. (Além disso, o acima é um UnicodeError no Python 2.)
O
unicode_escape
codec, apesar do nome, supõe que todos os bytes não ASCII estão na codificação Latin-1 (ISO-8859-1). Então você teria que fazer assim:Mas isso é terrível. Isso limita você aos 256 caracteres Latin-1, como se o Unicode nunca tivesse sido inventado!
Adicionando uma expressão regular para resolver o problema
(Surpreendentemente, não temos agora dois problemas.)
O que precisamos fazer é apenas aplicar o
unicode_escape
decodificador a coisas que temos certeza que são texto ASCII. Em particular, podemos ter certeza de aplicá-lo apenas a sequências de escape válidas do Python, que são garantidamente texto ASCII.O plano é encontrar sequências de escape usando uma expressão regular e usar uma função como o argumento
re.sub
para substituí-las por seu valor sem escape.E com isso:
fonte
os.sep
tudo? Estou tentando fazer isso:patt = '^' + self.prefix + os.sep ; name = sub(decode_escapes(patt), '', name)
e não está funcionando. O ponto-e-vírgula substitui uma nova linha.os.sep
é?) Se você tiver as sequências de escape com barra invertida nos nomes de diretório do Windows, a situação é praticamente irrecuperável.A resposta realmente correta e conveniente para Python 3:
Detalhes sobre
codecs.escape_decode
:codecs.escape_decode
é um decodificador de bytes para bytescodecs.escape_decode
decodifica sequências de escape ascii, como:b"\\n"
->b"\n"
,b"\\xce"
->b"\xce"
.codecs.escape_decode
não se importa ou precisa saber sobre a codificação do objeto de byte, mas a codificação dos bytes de escape deve corresponder à codificação do resto do objeto.Fundo:
unicode_escape
é a solução incorreta para python3. Isso ocorre porqueunicode_escape
decodifica bytes de escape e, em seguida, decodifica bytes para string Unicode, mas não recebe nenhuma informação sobre qual codec usar para a segunda operação.codecs.escape_decode
pela primeira vez com esta resposta para "como faço para .decode ('string-escape') em Python3?" . Como afirma essa resposta, essa função não está documentada atualmente para Python 3.fonte
\x
escapes de bytes UTF-8. Mas como ele decodifica bytes em bytes, ele não decodifica - e não pode - decodificar quaisquer escapes de caracteres Unicode não ASCII, como\u
escapes.A
ast.literal_eval
função chega perto, mas espera que a string seja devidamente citada primeiro.É claro que a interpretação do Python dos escapes de barra invertida depende de como a string está entre aspas (
""
vsr""
vsu""
, aspas triplas, etc), então você pode querer envolver a entrada do usuário em aspas adequadas e passar paraliteral_eval
. Colocá-lo entre aspas também impedirá oliteral_eval
retorno de um número, tupla, dicionário, etc.As coisas ainda podem ficar complicadas se o usuário digitar aspas sem aspas do tipo que você pretende envolver na string.
fonte
myString = "\"\ndoBadStuff()\n\""
,print(ast.literal_eval('"' + myString + '"'))
parece tentar executar código. Como éast.literal_eval
diferente / mais seguro do queeval
?literal_eval
nunca executa código. Na documentação, "Isso pode ser usado para avaliar com segurança strings que contêm expressões Python de fontes não confiáveis, sem a necessidade de analisar os valores por conta própria."Esta é uma maneira ruim de fazer isso, mas funcionou para mim ao tentar interpretar octais escapados passados em um argumento de string.
Vale a pena mencionar que há uma diferença entre eval e ast.literal_eval (eval sendo muito mais inseguro). Consulte Usando eval () do python vs. ast.literal_eval ()?
fonte
O código abaixo deve funcionar para \ n é necessário para ser exibido na string.
fonte
replace
não fazem nada), usa APIs totalmente desatualizadas (asstring
funções de módulo desse tipo foram descontinuadas no Python 2.0, substituídas pelosstr
métodos e foram completamente para o Python 3), e apenas lida com o caso específico de substituição de uma única nova linha, não com o processamento de escape geral.