Que font exactement les drapeaux de chaîne «u» et «r», et que sont les littéraux de chaîne bruts?

652

En posant cette question , j'ai réalisé que je ne connaissais pas grand-chose aux cordes brutes. Pour quelqu'un qui prétend être un entraîneur Django, ça craint.

Je sais ce qu'est un encodage, et je sais ce que u''seul fait puisque j'obtiens ce qui est Unicode.

  • Mais que fait r''-il exactement? À quel type de chaîne cela donne-t-il?

  • Et surtout, que fait le diable ur''?

  • Enfin, existe-t-il un moyen fiable de revenir d'une chaîne Unicode à une simple chaîne brute?

  • Ah, et au fait, si votre système et votre jeu de caractères de l'éditeur de texte sont définis sur UTF-8, est u''-ce que ça fait vraiment quelque chose?

e-satis
la source

Réponses:

683

Il n'y a pas vraiment de " chaîne brute "; il existe des littéraux de chaîne bruts , qui sont exactement les littéraux de chaîne marqués d'un 'r'avant la citation d'ouverture.

Un "littéral de chaîne brut" est une syntaxe légèrement différente pour un littéral de chaîne, dans laquelle une barre oblique inverse, \est considérée comme signifiant "juste une barre oblique inverse" (sauf lorsqu'elle vient juste avant une citation qui autrement mettrait fin au littéral) - non "séquences d'échappement" pour représenter les nouvelles lignes, les tabulations, les espaces arrière, les flux de formulaires, etc. Dans les littéraux de chaîne normaux, chaque barre oblique inverse doit être doublée pour éviter d'être considérée comme le début d'une séquence d'échappement.

Cette variante de syntaxe existe principalement parce que la syntaxe des modèles d'expression régulière est lourde de barres obliques inverses (mais jamais à la fin, donc la clause "except" ci-dessus n'a pas d'importance) et elle semble un peu meilleure lorsque vous évitez de doubler chacun d'eux - - c'est tout. Il a également gagné en popularité pour exprimer les chemins de fichiers natifs de Windows (avec des barres obliques inverses au lieu de barres obliques normales comme sur d'autres plates-formes), mais cela est très rarement nécessaire (car les barres obliques normales fonctionnent généralement bien sur Windows aussi) et imparfaites (en raison de la clause "except") au dessus de).

r'...'est une chaîne d'octets (en Python 2. *), ur'...'est une chaîne Unicode (encore une fois, en Python 2. *), et l' un des trois autres types de produit citant aussi exactement les mêmes types de cordes (ainsi , par exemple r'...', r'''...''', r"...", r"""..."""sont toutes des chaînes d'octets, etc.).

Je ne sais pas ce que vous entendez par " revenir en arrière " - il n'y a pas de sens intrinsèque en arrière et en avant, car il n'y a pas de type de chaîne brute , c'est juste une syntaxe alternative pour exprimer des objets de chaîne parfaitement normaux, octets ou unicode tels qu'ils peuvent être.

Et oui, en Python 2. *, u'...' est bien sûr toujours distinct de juste '...'- le premier est une chaîne unicode, le dernier est une chaîne d'octets. Dans quel codage le littéral pourrait être exprimé est un problème complètement orthogonal.

Par exemple, considérez (Python 2.6):

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

L'objet Unicode prend bien sûr plus d'espace mémoire (très petite différence pour une chaîne très courte, évidemment ;-).

Alex Martelli
la source
6
Comprendre "r" n'implique aucun problème de type ou d'encodage, c'est beaucoup plus simple.
e-satis
23
Notez que ru "C: \ foo \ unstable" échouera car \ u est une séquence d'échappement unicode en mode ru. le mode r n'a pas \ u.
Curtis Yallop
26
Notez que uet rne sont pas commutatifs: ur'str'fonctionne, ne fonctionne ru'str'pas. (au moins dans ipython 2.7.2 sur win7)
RafiK
7
Je viens de tester les rchaînes et j'ai remarqué que si \ c'est le dernier caractère, il ne sera pas pris comme un littéral mais échappera à la place à la citation de fermeture, ce qui provoquera SyntaxError: EOL while scanning string literal. Il \\ faut donc toujours utiliser l'instance finale de \ dans toutes les chaînes se terminant par une barre oblique inverse.
Enteleform
1
python 3.x - sys.getsizeof('cioa') == sys.getsizeof(r'cioa') == sys.getsizeof(u'cioa')(Ubuntu 16.04 avec UTF8 lang). De même, type('cioa') == type(r'cioa') == type(u'cioa'). MAIS, l'interpolation de chaîne brute fait une différence, alorssys.getsizeof('\ncioa') == sys.getsizeof(u'\ncioa') != sys.getsizeof(r'\ncioa')
Darren Weber
177

Il existe deux types de chaîne en python: le strtype traditionnel et le unicodetype plus récent . Si vous tapez un littéral de chaîne sans le udevant vous obtenez l'ancien strtype qui stocke les caractères 8 bits, et avec le udevant vous obtenez le plus récentunicode type qui peut stocker n'importe quel caractère Unicode.

Le rne change pas du tout le type, il change juste la façon dont le littéral de chaîne est interprété. Sans le r, les barres obliques inverses sont traitées comme des caractères d'échappement. Avec le r, les barres obliques inverses sont traitées comme littérales. De toute façon, le type est le même.

ur est bien sûr une chaîne Unicode où les barres obliques inverses sont des barres obliques inverses littérales, qui ne font pas partie des codes d'échappement.

Vous pouvez essayer de convertir une chaîne Unicode en une ancienne chaîne à l'aide de la str()fonction, mais s'il existe des caractères Unicode qui ne peuvent pas être représentés dans l'ancienne chaîne, vous obtiendrez une exception. Vous pouvez d'abord les remplacer par des points d'interrogation si vous le souhaitez, mais bien sûr, cela rendrait ces caractères illisibles. Il n'est pas recommandé d'utiliser le strtype si vous souhaitez gérer correctement les caractères unicode.

Mark Byers
la source
Merci, accepté. Comme je l'ai dit, j'ai compris ce qu'est unicode, je ne savais pas ce que "r" voulait dire et quelle serait la combinaison de "u" et "r". Je sais mieux savoir, applaudissements.
e-satis
6
Les barres obliques inverses ne sont pas traitées comme des littéraux dans les littéraux de chaîne bruts, c'est pourquoi il r"\"s'agit d'une erreur de syntaxe.
4
Ne s'applique qu'à Python 2.
PaulMcG
60

«chaîne brute» signifie qu'elle est stockée telle qu'elle apparaît. Par exemple, '\'c'est juste une barre oblique inverse au lieu d'un échappement .

xiaolong
la source
3
... sauf s'il s'agit du dernier caractère de la chaîne, auquel cas il échappe à la citation de fermeture.
jez
36

Un préfixe "u" indique que la valeur a un type unicodeplutôt que str.

Les littéraux de chaîne bruts, avec un préfixe "r", échappent à toutes les séquences d'échappement en leur sein, tout len(r"\n")comme 2. Comme ils échappent aux séquences d'échappement, vous ne pouvez pas terminer un littéral de chaîne avec une seule barre oblique inverse: ce n'est pas une séquence d'échappement valide (par exemple r"\").

"Raw" ne fait pas partie du type, c'est simplement une façon de représenter la valeur. Par exemple, "\\n"et r"\n"sont des valeurs identiques, tout comme 32, 0x20et 0b100000sont identiques.

Vous pouvez avoir des littéraux de chaîne brute unicode:

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

L'encodage du fichier source détermine simplement comment interpréter le fichier source, il n'affecte pas les expressions ou les types autrement. Cependant, il est recommandé d'éviter le code où un encodage autre que ASCII changerait la signification:

Les fichiers utilisant ASCII (ou UTF-8, pour Python 3.0) ne doivent pas avoir de cookie de codage. Latin-1 (ou UTF-8) ne doit être utilisé que lorsqu'un commentaire ou une docstring doit mentionner un nom d'auteur qui nécessite Latin-1; sinon, l'utilisation de \ x, \ u ou \ U est la meilleure façon d'inclure des données non ASCII dans les littéraux de chaîne.


la source
30

Permettez-moi de l'expliquer simplement: en python 2, vous pouvez stocker une chaîne dans 2 types différents.

Le premier est ASCII qui est de type str en python, il utilise 1 octet de mémoire. (256 caractères, stockera principalement des alphabets anglais et des symboles simples)

Le 2ème type est UNICODE qui est de type unicode en python. Unicode stocke tous les types de langues.

Par défaut, python préférera le type str mais si vous voulez stocker une chaîne en type unicode vous pouvez mettre u devant le texte comme u'text ' ou vous pouvez le faire en appelant unicode (' text ')

Donc, u est juste un moyen rapide d'appeler une fonction pour convertir str en unicode . C'est ça!

Maintenant, la partie r , vous le placez devant le texte pour dire à l'ordinateur que le texte est du texte brut, la barre oblique inverse ne doit pas être un caractère d'échappement. r '\ n' ne créera pas de nouveau caractère de ligne. C'est juste du texte brut contenant 2 caractères.

Si vous voulez convertir str en unicode et y mettre également du texte brut, utilisez ur car ru soulèvera une erreur.

MAINTENANT, la partie importante:

Vous ne pouvez pas stocker une barre oblique inverse à l'aide de r , c'est la seule exception. Donc, ce code produira une erreur: r '\'

Pour stocker une barre oblique inverse (une seule), vous devez utiliser '\\'

Si vous souhaitez stocker plus de 1 caractères, vous pouvez toujours utiliser r comme r '\\' produira 2 barres obliques inverses comme vous vous y attendiez.

Je ne connais pas la raison pour laquelle r ne fonctionne pas avec un seul stockage de barre oblique inverse, mais la raison n'est encore décrite par personne. J'espère que c'est un bug.

off99555
la source
9
Vous remarquerez non seulement qu'il r'\'est illégal, mais que vous ne pouvez même pas en mettre un '\'à la queue d'une corde. Tout comme r'xxxxxx\'une chaîne illégale.
plongeur
qu'en est-il de python 3?
Krissh
1
@Krissh Toutes les chaînes python 3 sont prises en charge Unicode. Son type sera str. En savoir plus pour une meilleure compréhension ici: medium.com/better-programming/…
off99555
4

C'est peut-être évident, peut-être pas, mais vous pouvez créer la chaîne '\' en appelant 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
la source
4
x is yévalue à True en python3?
Habeeb Perwad
5
@HabeebPerwad, c'est à cause de l' internement de chaînes . Vous ne devriez jamais vous fier au fait qu'il vous x is yarrive d'évaluer à Truecause d'un internat. Utilisez plutôt x == y(si vous ne vérifiez pas si x et y sont exactement le même objet stocké à une seule position de mémoire, c'est-à-dire).
Lucubrator
4

Littéraux de chaîne Unicode

Les littéraux de chaîne Unicode (littéraux de chaîne précédés de u) ne sont plus utilisés dans Python 3. Ils sont toujours valides mais uniquement à des fins de compatibilité avec Python 2.

Littéraux de chaîne bruts

Si vous voulez créer une chaîne littérale composée de seulement facilement des caractères typables comme des lettres anglaises ou des chiffres, vous pouvez simplement les taper: 'hello world'. Mais si vous souhaitez inclure également des personnages plus exotiques, vous devrez utiliser une solution de contournement. L'une des solutions est les séquences d'échappement . De cette façon, vous pouvez par exemple représenter une nouvelle ligne dans votre chaîne simplement en ajoutant deux caractères facilement saisissables \nà votre littéral de chaîne. Ainsi, lorsque vous imprimez la 'hello\nworld'chaîne, les mots seront imprimés sur des lignes distinctes. C'est très pratique!

D'un autre côté, il existe certaines situations où vous souhaitez créer un littéral de chaîne contenant des séquences d'échappement mais que vous ne souhaitez pas qu'elles soient interprétées par Python. Vous voulez qu'ils soient bruts . Regardez ces exemples:

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

Dans de telles situations, vous pouvez simplement préfixer le littéral de chaîne avec le rcaractère comme ceci: r'hello\nworld'et aucune séquence d'échappement ne sera interprétée par Python. La chaîne sera imprimée exactement comme vous l'avez créée.

Les littéraux de chaîne bruts ne sont pas complètement "bruts"?

Beaucoup de gens s'attendent à ce que les littéraux de chaîne bruts soient bruts dans un sens que "tout ce qui est placé entre les guillemets est ignoré par Python" . Ce n'est pas vrai. Python reconnaît toujours toutes les séquences d'échappement, il ne les interprète tout simplement pas - il les laisse inchangées à la place. Cela signifie que les littéraux de chaîne bruts doivent toujours être des littéraux de chaîne valides .

De la définition lexicale d'un littéral de chaîne:

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

Il est clair que les littéraux de chaîne (bruts ou non) contenant un caractère guillemet nu: 'hello'world'ou se terminant par une barre oblique inversée: 'hello world\'ne sont pas valides.

Jeyekomon
la source