O que exatamente fazem os sinalizadores de cadeia "u" e "r" e o que são literais de cadeia bruta?

652

Ao fazer essa pergunta , percebi que não sabia muito sobre strings não processadas. Para alguém que afirma ser um treinador de Django, isso é péssimo.

Sei o que é uma codificação e sei o que u''faz sozinho desde que recebo o que é Unicode.

  • Mas o que r''faz exatamente? Em que tipo de string ele resulta?

  • E acima de tudo, o que diabos faz ur''?

  • Finalmente, existe alguma maneira confiável de voltar de uma string Unicode para uma string simples simples?

  • Ah, e a propósito, se o seu sistema e o conjunto de caracteres do editor de texto estiverem definidos como UTF-8, ele u''realmente faz alguma coisa?

e-satis
fonte

Respostas:

683

Não há realmente nenhuma " string bruta "; existem literais de string brutos , que são exatamente os literais de string marcados com um 'r'antes da citação de abertura.

Um "literal de cadeia de caracteres brutos" é uma sintaxe ligeiramente diferente para um literal de cadeia de caracteres, na qual uma barra invertida \é entendida como significando "apenas uma barra invertida" (exceto quando ocorre logo antes de uma citação que de outra forma terminaria o literal) - não "seqüências de escape" para representar novas linhas, guias, backspaces, feeds de formulário e assim por diante. Em literais de sequência normal, cada barra invertida deve ser dobrada para evitar ser tomada como o início de uma sequência de escape.

Essa variante de sintaxe existe principalmente porque a sintaxe dos padrões de expressão regular é pesada com barras invertidas (mas nunca no final, portanto a cláusula "exceto" acima não importa) e fica um pouco melhor quando você evita dobrar cada uma delas - - Isso é tudo. Também ganhou popularidade ao expressar caminhos de arquivos nativos do Windows (com barras invertidas em vez de barras normais, como em outras plataformas), mas isso é muito raramente necessário (já que as barras normais também funcionam bem no Windows também) e imperfeito (devido à cláusula "exceto" acima).

r'...'é uma seqüência de byte (em Python 2. *), ur'...'é uma cadeia Unicode (novamente, em Python 2. *), e qualquer um dos outros três tipos de citar também produz exatamente os mesmos tipos de cordas (assim, por exemplo r'...', r'''...''', r"...", r"""..."""são todas cadeias de bytes e assim por diante).

Não sei ao certo o que você quer dizer com " voltar " - não há instruções intrinsecamente para trás e para frente, porque não há tipo de string bruto , é apenas uma sintaxe alternativa para expressar objetos de string perfeitamente normais, byte ou unicode, como podem ser.

E sim, no Python 2. *, u'...' é claro que sempre é diferente de apenas '...'- o primeiro é uma string unicode, o último é uma string de bytes. A codificação do literal pode ser expressa em uma questão completamente ortogonal.

Por exemplo, considere (Python 2.6):

>>> sys.getsizeof('ciao')
28
>>> sys.getsizeof(u'ciao')
34

Obviamente, o objeto Unicode ocupa mais espaço na memória (diferença muito pequena para uma string muito curta, obviamente ;-).

Alex Martelli
fonte
6
Entender "r" não implica nenhum tipo ou problema de codificação, é muito mais simples.
e-satis
23
Observe que ru "C: \ foo \ unstable" falhará porque \ u é uma sequência de escape unicode no modo ru. O modo r não possui \ u.
Curtis Yallop
26
Observe que ue rnão são comutativos: ur'str'funciona, ru'str'não funciona . (pelo menos em ipython 2.7.2 em win7)
rafik
7
Acabei de testar as rstrings e percebi que se \ for o último caractere, ele não será tomado como literal, mas escapará da citação final, causando SyntaxError: EOL while scanning string literal. Portanto, \\ ainda deve ser usado para a instância final de \ qualquer sequência que termine com uma barra invertida.
Enteleform
1
python 3.x - sys.getsizeof('cioa') == sys.getsizeof(r'cioa') == sys.getsizeof(u'cioa')(Ubuntu 16.04 com UTF8 lang). Da mesma forma type('cioa') == type(r'cioa') == type(u'cioa'),. MAS, a interpolação corda crua faz a diferença, entãosys.getsizeof('\ncioa') == sys.getsizeof(u'\ncioa') != sys.getsizeof(r'\ncioa')
Darren Weber
177

Existem dois tipos de string em python: o strtipo tradicional e o unicodetipo mais recente . Se você digitar uma string literal sem o una frente, obtém o strtipo antigo, que armazena caracteres de 8 bits, e com o una frente, o unicodetipo mais recente que pode armazenar qualquer caractere Unicode.

O rnão muda o tipo, apenas muda a maneira como a string literal é interpretada. Sem o r, as barras invertidas são tratadas como caracteres de escape. Com o r, as barras invertidas são tratadas como literais. De qualquer maneira, o tipo é o mesmo.

ur é obviamente uma string Unicode em que as barras invertidas são barras invertidas literais, não parte dos códigos de escape.

Você pode tentar converter uma string Unicode em uma string antiga usando a str()função, mas se houver algum caractere unicode que não possa ser representado na string antiga, você receberá uma exceção. Você pode substituí-los por pontos de interrogação primeiro, se desejar, mas é claro que isso tornaria esses caracteres ilegíveis. Não é recomendável usar o strtipo se você deseja manipular corretamente caracteres unicode.

Mark Byers
fonte
Obrigado, aceito. Como eu disse, eu sabia o que é unicode, não sabia o que "r" significava e qual seria a combinação de "u" e "r". Eu sei melhor, aplausos.
e-satis
6
As barras invertidas não são tratadas como literais em literais de cadeia bruta, e é por isso que r"\"ocorre um erro de sintaxe.
4
Só se aplica a Python 2.
PaulMcG
60

'sequência bruta' significa que é armazenada como aparece. Por exemplo, '\'é apenas uma barra invertida em vez de uma fuga .

xiaolong
fonte
3
... a menos que seja o último caractere da sequência, nesse caso, ela escapará da citação final.
Jez
36

Um prefixo "u" indica que o valor tem tipo unicodee não str.

Literais de string brutos, com um prefixo "r", escapam de quaisquer seqüências de escape dentro deles, assim len(r"\n")como 2. Como eles escapam de seqüências de escape, não é possível terminar um literal de string com uma única barra invertida: essa não é uma sequência de escape válida (por exemplo r"\").

"Bruto" não faz parte do tipo, é apenas uma maneira de representar o valor. Por exemplo, "\\n"e r"\n"são valores idênticos, assim como 32, 0x20, e 0b100000são idênticos.

Você pode ter literais de cadeia bruta unicode:

>>> u = ur"\n"
>>> print type(u), len(u)
<type 'unicode'> 2

A codificação do arquivo de origem apenas determina como interpretar o arquivo de origem; caso contrário, não afeta expressões ou tipos. No entanto, é recomendável evitar código em que uma codificação diferente de ASCII altere o significado:

Arquivos usando ASCII (ou UTF-8, para Python 3.0) não devem ter um cookie de codificação. O Latin-1 (ou UTF-8) deve ser usado apenas quando um comentário ou uma doutrina precisar mencionar um nome de autor que exija o Latin-1; caso contrário, usar escapes \ x, \ u ou \ U é a maneira preferida de incluir dados não ASCII em literais de string.


fonte
30

Deixe-me explicar de maneira simples: no python 2, você pode armazenar a string em 2 tipos diferentes.

O primeiro é ASCII que é str tipo em python, ele usa 1 byte de memória. (256 caracteres, armazenará principalmente alfabetos ingleses e símbolos simples)

O segundo tipo é UNICODE, que é do tipo unicode em python. Unicode armazena todos os tipos de idiomas.

Por padrão, o python prefere o tipo str, mas se você deseja armazenar a string no tipo unicode, pode colocar u na frente do texto como u'text ' ou pode fazer isso chamando unicode (' text ')

Então você é apenas uma maneira curta de chamar uma função para converter str em unicode . É isso aí!

Agora, na parte r , você o coloca na frente do texto para informar ao computador que o texto é texto bruto, a barra invertida não deve ser um caractere de escape. r '\ n' não criará um novo caractere de linha. É apenas texto sem formatação contendo 2 caracteres.

Se você deseja converter str para unicode e também colocar texto bruto, use ur porque o ru causará um erro.

AGORA, a parte importante:

Você não pode armazenar uma barra invertida usando r , é a única exceção. Portanto, este código produzirá erro: r '\'

Para armazenar uma barra invertida (apenas uma), você precisa usar '\\'

Se você deseja armazenar mais de 1 caracteres, ainda pode usar r como r '\\' produzirá duas barras invertidas conforme o esperado.

Não sei o motivo pelo qual r não funciona com um armazenamento com barra invertida, mas o motivo ainda não foi descrito por ninguém. Espero que seja um bug.

off99555
fonte
9
Você notará que não apenas r'\'é ilegal, como também não pode colocar um único '\'na cauda de nenhuma corda. Assim como r'xxxxxx\'é uma string ilegal.
diverger
e quanto ao python 3?
Krissh 10/09/19
1
@ Krissh Todas as strings do python 3 são suportadas por Unicode. O seu tipo será str. Leia mais para uma melhor compreensão aqui: medium.com/better-programming/…
off99555
4

Talvez isso seja óbvio, talvez não, mas você pode criar a string '\' chamando x = chr (92)

x=chr(92)
print type(x), len(x) # <type 'str'> 1
y='\\'
print type(y), len(y) # <type 'str'> 1
x==y   # True
x is y # False
Bomba Ps
fonte
4
x is yavalia como True em python3?
Habeeb Perwad
5
@HabeebPerwad, isso é devido à internação de strings . Você nunca deve confiar no fato de x is yser avaliado por Truecausa da internação. Em vez disso, use x == y(se você não estiver verificando se xey são exatamente o mesmo objeto armazenado em uma única posição de memória).
Lucrubrator #
4

Literais de seqüência de caracteres Unicode

Literais de strings Unicode (literais de strings prefixados por u) não são mais usados no Python 3. Eles ainda são válidos, mas apenas para fins de compatibilidade com o Python 2.

Literais de cadeia bruta

Se você deseja criar uma string literal consistindo de apenas caracteres facilmente tipáveis como letras inglesas ou números, você pode simplesmente digitá-los: 'hello world'. Mas se você quiser incluir também alguns personagens mais exóticos, precisará usar algumas soluções alternativas. Uma das soluções alternativas são as seqüências de escape . Dessa forma, você pode, por exemplo, representar uma nova linha na sua string simplesmente adicionando dois caracteres facilmente digitáveis \nao literal da string. Portanto, quando você imprimir a 'hello\nworld'sequência, as palavras serão impressas em linhas separadas. Isso é muito útil!

Por outro lado, há algumas situações em que você deseja criar uma string literal que contém seqüências de escape, mas não deseja que elas sejam interpretadas pelo Python. Você quer que eles sejam crus . Veja estes exemplos:

'New updates are ready in c:\windows\updates\new'
'In this lesson we will learn what the \n escape sequence does.'

Em tais situações, você pode simplesmente prefixar a string literal com o rcaractere como este: r'hello\nworld'e nenhuma sequência de escape será interpretada pelo Python. A sequência será impressa exatamente como você a criou.

Literais de cadeia bruta não são completamente "brutos"?

Muitas pessoas esperam que os literais de strings brutos sejam brutos no sentido de que "qualquer coisa colocada entre as aspas é ignorada pelo Python" . Isso não é verdade. O Python ainda reconhece todas as seqüências de escape, simplesmente não as interpreta - as deixa inalteradas. Isso significa que os literais de cadeia brutos ainda precisam ser literais de cadeia válidos .

A partir da definição lexical de uma string literal:

string     ::=  "'" stringitem* "'"
stringitem ::=  stringchar | escapeseq
stringchar ::=  <any source character except "\" or newline or the quote>
escapeseq  ::=  "\" <any source character>

É claro que literais de string (brutos ou não) contendo um caractere de aspas simples: 'hello'world'ou terminando com uma barra invertida: 'hello world\'não são válidos.

Jeyekomon
fonte