¿Qué hacen exactamente los indicadores de cadena "u" y "r", y qué son los literales de cadena sin formato?

652

Al hacer esta pregunta , me di cuenta de que no sabía mucho sobre cadenas sin formato. Para alguien que dice ser un entrenador de Django, esto apesta.

Sé lo que es una codificación, y sé lo que u''hace solo desde que obtengo lo que es Unicode.

  • ¿Pero qué hace r''exactamente? ¿En qué tipo de cadena resulta?

  • Y, sobre todo, ¿qué diablos hace ur''?

  • Finalmente, ¿hay alguna forma confiable de regresar de una cadena Unicode a una cadena simple sin procesar?

  • Ah, y por cierto, si su sistema y su conjunto de caracteres de editor de texto están configurados en UTF-8, ¿ u''realmente hace algo?

e-satis
fuente

Respuestas:

683

Realmente no hay ninguna " cadena cruda "; hay literales de cadena sin procesar , que son exactamente los literales de cadena marcados con un 'r'antes de la cita de apertura.

Un "literal de cadena sin formato" es una sintaxis ligeramente diferente para un literal de cadena, en el que una barra diagonal inversa \se toma como "solo una barra diagonal inversa" (excepto cuando aparece justo antes de una cita que de lo contrario terminaría el literal) - no "secuencias de escape" para representar nuevas líneas, pestañas, espacios de retroceso, alimentación de formularios, etc. En los literales de cadena normales, cada barra invertida debe duplicarse para evitar ser tomada como el inicio de una secuencia de escape.

Esta variante de sintaxis existe principalmente porque la sintaxis de los patrones de expresión regular es pesada con barras invertidas (pero nunca al final, por lo que la cláusula "excepto" anterior no importa) y se ve un poco mejor cuando evita duplicar cada una de ellas. - eso es todo. También ganó algo de popularidad para expresar rutas de archivos nativas de Windows (con barras diagonales inversas en lugar de barras diagonales regulares como en otras plataformas), pero eso es muy raro (ya que las barras diagonales normales también funcionan bien en Windows) e imperfecto (debido a la cláusula "excepto" encima).

r'...'es una cadena de bytes (en Python 2. *), ur'...'es una cadena Unicode (de nuevo, en Python 2. *), y cualquiera de los otros tres tipos de citar también produce exactamente los mismos tipos de cuerdas (así por ejemplo r'...', r'''...''', r"...", r"""..."""son todas cadenas de bytes, y así sucesivamente).

No estoy seguro de lo que quiere decir con " retroceder ": no hay direcciones intrínsecamente hacia atrás y hacia adelante, porque no hay un tipo de cadena sin procesar , es solo una sintaxis alternativa para expresar objetos de cadena perfectamente normales, byte o unicode, como pueden ser.

Y sí, en Python 2. *, u'...' es decir , por supuesto, siempre distinto de simplemente '...'- el primero es una cadena Unicode, esta última es una cadena de bytes. La codificación del literal podría expresarse en un problema completamente ortogonal.

Por ejemplo, considere (Python 2.6):

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

El objeto Unicode, por supuesto, ocupa más espacio en la memoria (muy poca diferencia para una cadena muy corta, obviamente ;-).

Alex Martelli
fuente
66
Comprender "r" no implica ningún tipo de problema de codificación, es mucho más simple.
e-satis
23
Tenga en cuenta que ru "C: \ foo \ inestable" fallará porque \ u es una secuencia de escape unicode en modo ru. El modo r no tiene \ u.
Curtis Yallop
26
Tenga en cuenta que uy rno son conmutativos: ur'str'funciona, ru'str'no. (al menos en ipython 2.7.2 en win7)
RafiK
77
Simplemente probé las rcadenas y noté que si \ es el último carácter, no se tomará como un literal, sino que se escapará de la cita de cierre, causando SyntaxError: EOL while scanning string literal. Por lo tanto, \\ aún debe usarse para la instancia final de \ cualquier cadena que termine con una barra diagonal inversa.
Enteleform
1
python 3.x - sys.getsizeof('cioa') == sys.getsizeof(r'cioa') == sys.getsizeof(u'cioa')(Ubuntu 16.04 con UTF8 lang). Del mismo modo, type('cioa') == type(r'cioa') == type(u'cioa'). PERO, la interpolación de cadena sin formato hace la diferencia, entoncessys.getsizeof('\ncioa') == sys.getsizeof(u'\ncioa') != sys.getsizeof(r'\ncioa')
Darren Weber
177

Hay dos tipos de cadenas en python: el strtipo tradicional y el unicodetipo más nuevo . Si escribe un literal de cadena sin el ufrente, obtiene el strtipo antiguo que almacena caracteres de 8 bits, y con el ufrente obtiene el unicodetipo más nuevo que puede almacenar cualquier carácter Unicode.

El rno cambia el tipo en absoluto, solo cambia la forma en que se interpreta el literal de cadena. Sin el r, las barras invertidas se tratan como caracteres de escape. Con las rbarras invertidas se tratan como literales. De cualquier manera, el tipo es el mismo.

ur es, por supuesto, una cadena Unicode donde las barras diagonales inversas son barras diagonales inversas, no forman parte de los códigos de escape.

Puede intentar convertir una cadena Unicode en una cadena antigua utilizando la str()función, pero si hay caracteres Unicode que no se pueden representar en la cadena antigua, obtendrá una excepción. Puede reemplazarlos con signos de interrogación primero si lo desea, pero, por supuesto, esto haría que esos caracteres sean ilegibles. No se recomienda usar el strtipo si desea manejar correctamente los caracteres unicode.

Mark Byers
fuente
Gracias aceptado. Como dije, comprendí qué es unicode, no sabía qué significaba "r" y cuál sería la combinación de "u" y "r". Lo sé, mejor, saludos.
e-satis
66
Las barras diagonales inversas no se tratan como literales en los literales de cadena sin formato, por lo que se r"\"trata de un error de sintaxis.
44
Solo se aplica a Python 2.
PaulMcG
60

'cadena sin procesar' significa que se almacena como aparece. Por ejemplo, '\'es solo una barra invertida en lugar de un escape .

xiaolong
fuente
3
... a menos que sea el último carácter de la cadena, en cuyo caso escapa a la cita de cierre.
jez
36

Un prefijo "u" denota que el valor tiene tipo en unicodelugar de str.

Los literales de cadena sin procesar, con un prefijo "r", escapan de cualquier secuencia de escape dentro de ellos, por lo que len(r"\n")es 2. Debido a que escapan las secuencias de escape, no puede finalizar un literal de cadena con una barra invertida simple: esa no es una secuencia de escape válida (por ejemplo r"\").

"Raw" no es parte del tipo, es simplemente una forma de representar el valor. Por ejemplo, "\\n"y r"\n"son valores idénticos, al igual que 32, 0x20y 0b100000son idénticos.

Puede tener literales de cadena sin formato Unicode:

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

La codificación del archivo fuente solo determina cómo interpretar el archivo fuente, de lo contrario no afecta a las expresiones o tipos. Sin embargo, se recomienda evitar el código donde una codificación distinta de ASCII cambiaría el significado:

Los archivos que usan ASCII (o UTF-8, para Python 3.0) no deben tener una cookie de codificación. Latin-1 (o UTF-8) solo se debe utilizar cuando un comentario o una cadena de documentos necesita mencionar un nombre de autor que requiera Latin-1; de lo contrario, el uso de escapes \ x, \ u o \ U es la forma preferida de incluir datos no ASCII en literales de cadena.


fuente
30

Permítanme explicarlo simplemente: en python 2, puede almacenar cadenas en 2 tipos diferentes.

El primero es ASCII, que es tipo str en python, utiliza 1 byte de memoria. (256 caracteres, almacenarán principalmente alfabetos ingleses y símbolos simples)

El segundo tipo es UNICODE, que es de tipo unicode en python. Unicode almacena todo tipo de idiomas.

De forma predeterminada, Python preferirá el tipo de cadena, pero si desea almacenar la cadena en tipo unicode , puede colocar u delante del texto como u'text ' o puede hacerlo llamando a unicode (' text ')

Así que u es sólo una forma corta para llamar a una función de reparto str a Unicode . ¡Eso es!

Ahora la parte r , la pones delante del texto para decirle a la computadora que el texto es texto sin formato, la barra invertida no debe ser un carácter de escape. r '\ n' no creará un nuevo carácter de línea. Es solo texto sin formato que contiene 2 caracteres.

Si desea convertir str a unicode y también poner texto sin procesar allí, use ur porque ru generará un error.

AHORA, la parte importante:

No puede almacenar una barra invertida utilizando r , es la única excepción. Entonces este código producirá un error: r '\'

Para almacenar una barra invertida (solo una) necesita usar '\\'

Si desea almacenar más de 1 caracteres, puede usar r como r '\\' producirá 2 barras diagonales inversas como esperaba.

No sé la razón por la cual r no funciona con un almacenamiento de barra invertida, pero todavía no se describe la razón. Espero que sea un error.

off99555
fuente
99
Notarás que no solo r'\'es ilegal, sino que incluso no puedes poner '\'ninguno en la cola de ninguna cadena. Al igual que r'xxxxxx\'es una cadena ilegal.
diverger
¿Qué hay de Python 3?
Krissh
1
@Krissh Todas las cadenas de Python 3 son compatibles con Unicode. Su tipo será str. Lea más para una mejor comprensión aquí: medium.com/better-programming/…
off99555
4

Tal vez esto sea obvio, tal vez no, pero puede hacer la cadena '\' llamando a 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
fuente
44
x is yse evalúa como verdadero en python3?
Habeeb Perwad
55
@HabeebPerwad, eso se debe al internamiento de cadenas . Nunca debe confiar en el hecho de que se x is yevalúa Truepor internarse. En su lugar, use x == y(si no está comprobando si xey son exactamente el mismo objeto almacenado en una sola posición de memoria, es decir).
Lucubrator
4

Literales de cadena Unicode

Los literales de cadena Unicode (literales de cadena con el prefijo u) ya no se usan en Python 3. Todavía son válidos, pero solo para fines de compatibilidad con Python 2.

Literales de cadena sin procesar

Si desea crear una cadena literal que consta de sólo caracteres fácilmente tipificables como letras o números en inglés, sólo tiene que escribir ellos: 'hello world'. Pero si desea incluir también algunos personajes más exóticos, tendrá que usar una solución alternativa. Una de las soluciones son las secuencias de escape . De esta manera, por ejemplo, puede representar una nueva línea en su cadena simplemente agregando dos caracteres fáciles de escribir \na su literal de cadena. Entonces, cuando imprime la 'hello\nworld'cadena, las palabras se imprimirán en líneas separadas. Eso es muy útil!

Por otro lado, hay algunas situaciones en las que desea crear un literal de cadena que contenga secuencias de escape, pero no desea que Python las interprete. Quieres que estén crudos . Mira estos ejemplos:

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

En tales situaciones, puede simplemente prefijar el literal de cadena con el rcarácter de esta manera: r'hello\nworld'y Python no interpretará ninguna secuencia de escape. La cadena se imprimirá exactamente como la creó.

Los literales de cadena sin formato no son completamente "sin formato"?

Muchas personas esperan que los literales de cadena sin formato sean crudos en el sentido de que "Python ignora cualquier cosa colocada entre las comillas" . Eso no es verdad. Python todavía reconoce todas las secuencias de escape, simplemente no las interpreta, sino que las deja sin cambios. Significa que los literales de cadena sin procesar todavía tienen que ser literales de cadena válidos .

De la definición léxica de un literal de cadena:

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

Está claro que los literales de cadena (sin procesar o no) que contienen un carácter de comillas simples 'hello'world'o que terminan con una barra diagonal inversa 'hello world\'no son válidos.

Jeyekomon
fuente