Commit 299cd59c authored by Olivier Iffrig's avatar Olivier Iffrig

Initial import

Encoding, french version
parents
*.aux
*.log
*.out
text/fr/encoding/encoding.pdf
File added
File added
This diff is collapsed.
This diff is collapsed.
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="265.84323"
height="336.88248"
id="svg2"
version="1.1"
inkscape:version="0.48.5 r10040"
sodipodi:docname="pas_un_i.svg">
<defs
id="defs4" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.9899495"
inkscape:cx="86.916356"
inkscape:cy="128.59392"
inkscape:document-units="px"
inkscape:current-layer="g3031"
showgrid="false"
inkscape:window-width="1278"
inkscape:window-height="779"
inkscape:window-x="0"
inkscape:window-y="19"
inkscape:window-maximized="0"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0" />
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Calque 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-225.00554,-60.789898)">
<path
style="fill:none;stroke:#000000;stroke-width:1.00861812px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 227.56342,61.709795 c 0.0989,104.257645 -3.7876,241.493475 -1.11176,334.041755 91.02541,4.42814 183.97896,-3.24656 263.41727,0.0764 -0.93606,-117.40564 2.16951,-234.56633 -0.95936,-333.39151 -86.18245,-2.830647 -176.0481,0.667618 -261.34615,-0.726675 z"
id="path2985"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccc" />
<path
style="fill:none;stroke:#000000;stroke-width:0.98295301px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 249.95921,85.210846 c -3.02783,54.776514 2.48352,152.469394 1.38016,195.731174 69.5269,-4.4187 141.15438,5.93972 220.8259,-1.42869 1.7686,-70.15812 -3.05864,-135.19837 -1.38017,-193.588137 -46.50347,-2.600911 -161.13399,-0.237185 -220.82589,-0.714347 z"
id="path2987"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccc" />
<path
style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
id="path2989"
d="m 405.90108,124.95876 c 0,0 -3.10123,1.86446 -6.07943,4.14459 -21.66603,1.01744 -53.9231,-0.76465 -82.09984,0.25782 l 5.58167,-4.33638 c 21.02654,-0.002 58.57201,-0.8237 82.5976,-0.066 z"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccc" />
<path
style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
id="path2991"
d="m 363.8051,126.32197 c 0.30125,35.36272 -1.90105,65.07462 -0.50392,89.5651 -2.01683,0.0252 -3.52423,2.05556 -5.89981,3.74671 -1.79762,-14.15812 0.18436,-68.31736 0.0515,-90.2061 l 6.35251,-3.10571 z"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccc" />
<path
style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:2;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
id="path2993"
d="m 327.62395,215.86595 c 27.93573,1.38478 58.54758,-1.63646 79.77232,0.36947 0.008,0.0217 0.0154,0.0434 0.0231,0.0652 l -6.27365,3.40015 0,0 c -11.13422,-0.51538 -66.61236,1.33191 -78.19592,0.18468 2.53285,-2.20468 2.15879,-2.86166 4.67373,-4.01996 z"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccccc" />
<g
id="g3031">
<path
sodipodi:nodetypes="czc"
inkscape:connector-curvature="0"
id="path2995"
d="m 303.74024,244.55581 c -1.98074,9.75766 -1.64862,21.77272 7.07107,21.71828 8.71968,-0.0544 9.65267,-13.3589 9.91212,-21.52887"
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<g
transform="translate(-3.8512066,-2.841054)"
id="g3009">
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 338.2117,251.31121 c 0.59437,5.51829 -0.16392,12.80962 0.1894,16.16244"
id="path2997"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 329.94107,259.13989 c 4.64346,0.26065 11.21584,-0.46977 16.6044,-0.0631"
id="path2999"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
</g>
<path
sodipodi:nodetypes="zzzzz"
inkscape:connector-curvature="0"
id="path3001"
d="m 358.6058,246.12777 c -5.43536,-0.63517 -7.25724,4.04372 -7.48098,10.01638 -0.22375,5.97265 0.74806,9.4733 6.05497,10.50756 5.30691,1.03425 7.79118,-4.15069 8.38282,-9.91181 0.59163,-5.76111 -1.52144,-9.97696 -6.95681,-10.61213 z"
style="fill:none;stroke:#000000;stroke-width:1.05829108px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
sodipodi:nodetypes="czzzc"
inkscape:connector-curvature="0"
id="path3003"
d="m 372.19545,250.66722 c -2.14987,-7.85535 12.99036,-4.0544 13.42746,1.02675 0.43707,5.08115 -6.66636,6.28476 -6.66636,4.56097 0,-1.72379 8.04791,1.411 7.80402,5.59263 -0.24388,4.18164 -9.38596,7.51618 -15.29842,1.5807"
style="fill:none;stroke:#000000;stroke-width:0.96853048px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
sodipodi:nodetypes="czczc"
inkscape:connector-curvature="0"
id="path3007"
d="m 404.52787,252.18753 c -0.95017,-7.60975 -12.10839,-8.65405 -10.32721,-0.6803 1.78118,7.97375 10.08579,2.65486 10.39037,0.6803 0.99938,5.07465 1.08117,9.1403 -0.57045,11.92235 -1.65162,2.78205 -5.86845,3.39952 -10.46534,0.2822"
style="fill:none;stroke:#000000;stroke-width:0.94912004px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
sodipodi:nodetypes="czczc"
inkscape:connector-curvature="0"
id="path3007-9"
d="m 421.88174,252.60455 c -0.95017,-7.60975 -12.10839,-8.65405 -10.32721,-0.6803 1.78118,7.97375 10.08579,2.65486 10.39037,0.6803 0.99938,5.07465 1.08117,9.1403 -0.57045,11.92235 -1.65162,2.78205 -5.86845,3.39952 -10.46534,0.2822"
style="fill:none;stroke:#000000;stroke-width:0.94912004px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<text
xml:space="preserve"
style="font-size:48px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:85.00000238%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Allura;-inkscape-font-specification:Allura"
x="359.50348"
y="324.54727"
id="text3014"
sodipodi:linespacing="85.000002%"><tspan
sodipodi:role="line"
id="tspan3016"
x="364.75348"
y="324.54727">Ceci n'est </tspan><tspan
sodipodi:role="line"
x="359.50348"
y="365.34726"
id="tspan3018">pas un I.</tspan></text>
</g>
</g>
</svg>
This diff is collapsed.
\documentclass{article}
% Auteur : Olivier Iffrig
% Copyright : 2014 Olivier Iffrig
% Licence : CC-BY-SA (http://creativecommons.org/licenses/by-sa/4.0/)
\usepackage[utf8]{inputenc}
\usepackage[greek,french]{babel}
\usepackage[usenames,svgnames]{xcolor}
\usepackage[pdftex]{hyperref}
\usepackage{palatino}
\usepackage{graphicx}
\usepackage{listings}
\usepackage{tikz}
\usepackage{geometry}
\geometry{hmargin=1.5in}
\hypersetup{colorlinks,%
%citecolor=black,%
%filecolor=black,%
linkcolor=blue,%
urlcolor=blue%
}
\title{Le codage des caractères en Python}
\author{Olivier Iffrig}
\date{\today}
\lstset{literate=
{á}{{\'a}}1 {é}{{\'e}}1 {í}{{\'i}}1 {ó}{{\'o}}1 {ú}{{\'u}}1
{Á}{{\'A}}1 {É}{{\'E}}1 {Í}{{\'I}}1 {Ó}{{\'O}}1 {Ú}{{\'U}}1
{à}{{\`a}}1 {è}{{\`e}}1 {ì}{{\`i}}1 {ò}{{\`o}}1 {ù}{{\`u}}1
{À}{{\`A}}1 {È}{{\'E}}1 {Ì}{{\`I}}1 {Ò}{{\`O}}1 {Ù}{{\`U}}1
{ä}{{\"a}}1 {ë}{{\"e}}1 {ï}{{\"i}}1 {ö}{{\"o}}1 {ü}{{\"u}}1
{Ä}{{\"A}}1 {Ë}{{\"E}}1 {Ï}{{\"I}}1 {Ö}{{\"O}}1 {Ü}{{\"U}}1
{â}{{\^a}}1 {ê}{{\^e}}1 {î}{{\^i}}1 {ô}{{\^o}}1 {û}{{\^u}}1
{Â}{{\^A}}1 {Ê}{{\^E}}1 {Î}{{\^I}}1 {Ô}{{\^O}}1 {Û}{{\^U}}1
{œ}{{\oe}}1 {Œ}{{\OE}}1 {æ}{{\ae}}1 {Æ}{{\AE}}1 {ß}{{\ss}}1
{ç}{{\c c}}1 {Ç}{{\c C}}1 {ø}{{\o}}1 {å}{{\r a}}1 {Å}{{\r A}}1
{}{{\EUR}}1 {£}{{\pounds}}1
}
\lstset{ %
language=Python, %
keywordstyle=\color{DarkBlue}, %
keywordstyle=[2]\color{DarkGreen}, %
morekeywords={as,with}, %
morekeywords=[2]{bytes}, %
stringstyle=\color{DarkRed}, %
showstringspaces=false %
}
\lstdefinelanguage{PythonError}{%
breaklines=true,%
sensitive=true,%
keywordstyle=\color{Red},%
keywordstyle=[2]\color{Orange},
morekeywords={ArithmeticError,AssertionError,AttributeError,BaseException,%
BufferError,EOFError,EnvironmentError,Exception,FloatingPointError,%
GeneratorExit,IOError,ImportError,IndentationError,IndexError,KeyError,%
KeyboardInterrupt,LookupError,MemoryError,NameError,%
NotImplementedError,OSError,OverflowError,ReferenceError,RuntimeError,%
StandardError,StopIteration,SyntaxError,SystemError,SystemExit,TabError,%
TypeError,UnboundLocalError,UnicodeDecodeError,UnicodeEncodeError,%
UnicodeError,UnicodeTranslateError,ValueError,ZeroDivisionError},%
morekeywords=[2]{BytesWarning,DeprecationWarning,FutureWarning,%
ImportWarning,PendingDeprecationWarning,RuntimeWarning,SyntaxWarning,%
UnicodeWarning,UserWarning,Warning}%
}
\newcommand\gpic[3]{\begin{center}\includegraphics[#1]{#2}\\* #3\end{center}}
\newcommand\cpic[2]{\gpic{height=4cm}{#1}{#2}}
\newcommand\Cpic[2]{\cpic{#1}{\rule{0pt}{2ex} \tiny #2}}
\newcommand\pic[1]{\cpic{#1}{}}
\newcommand\vcpic[2]{\gpic{width=4cm}{#1}{#2}}
\newcommand\vCpic[2]{\vcpic{#1}{\rule{0pt}{2ex} \tiny #2}}
\newcommand\vpic[1]{\vcpic{#1}{}}
\newcommand\cc[1]{{\footnotesize #1}}
\begin{document}
\maketitle
\section*{Licence}
Cet article, ainsi que les images qu'il contient (sauf mention contraire
explicite) sont sous licence Creative Commons CC-BY-SA. Vous pouvez le copier et
le modifier à votre guise, à condition de citer l'auteur, de mettre en évidence
vos modifications et de partager les modifications sous la même licence. Pour
plus de détails : \url{http://creativecommons.org/licenses/by-sa/4.0/}
\section{Le co--- quoi ?}
Nos ordinateurs ne comprennent que le binaire, c'est à dire des 0 et des
1\footnote{pouvant être représentés physiquement de diverses manières, par
exemple un potentiel électrique inférieur ou supérieur à un seuil donné},
souvent regroupés par 8 (les octets).
\pic{../../../pic/bonjour.pdf}
Pour pouvoir représenter du texte dans ce système, il faut donc choisir une
re\-pré\-sen\-ta\-tion pour chaque caractère. C'est ce qu'ont fait un certain
nombre de gens, et vous vous imaginez bien qu'ils ne se sont pas concertés
avant, du coup, à la fin des années 50, chacun avait sa propre convention de
codage des caractères.
Afin d'arranger un peu les choses, l'ISO a décidé en 1960 de créer un comité
chargé des systèmes d'information, dont l'un des objectifs était de coordonner
les différentes conventions de codage. C'est ainsi que naît l'\emph{American
Standard Code for Information Interchange}, abrégé ASCII.
\begin{center}
\resizebox{.8\textwidth}{!}{
\begin{tabular}{c|cccccccccccccccc}
& .0 & .1 & .2 & .3 & .4 & .5 & .6 & .7 & .8 & .9 & .A & .B & .C & .D & .E & .F \\
\hline
0. & \cc{NUL} & \cc{SOH} & \cc{STX} & \cc{ETX} & \cc{EOT} & \cc{ENQ} & \cc{ACK} &
\cc{BEL} & \cc{BS} & \cc{HT} & \cc{LF} & \cc{VT} & \cc{FF} & \cc{CR} &
\cc{SO} & \cc{SI} \\
1. & \cc{DLE} & \cc{DC1} & \cc{DC2} & \cc{DC3} & \cc{DC4} & \cc{NAK} &
\cc{SYN} & \cc{ETB} & \cc{CAN} & \cc{EM} & \cc{SUB} & \cc{ESC} &
\cc{FS} & \cc{GS} & \cc{RS} & \cc{US} \\
2. & \cc{SP} & ! & " & \# & \$ & \% & \& & ' & ( & ) & * & + & , & - & . & / \\
3. & 0 & 1 & 2 & 3 & 4 & 5 & 6 & 7 & 8 & 9 & : & ; & $<$ & = & $>$ & ? \\
4. & @ & A & B & C & D & E & F & G & H & I & J & K & L & M & N & O \\
5. & P & Q & R & S & T & U & V & W & X & Y & Z & [ & \textbackslash & ] & \^{} & \_ \\
6. & \`{} & a & b & c & d & e & f & g & h & i & j & k & l & m & n & o \\
7. & p & q & r & s & t & u & v & w & x & y & z & \{ & | & \} & \~{} & \cc{DEL}
\end{tabular}
}\\*[.5ex]
La table des caractères ASCII
\end{center}
L'ASCII permet de représenter sur\hspace{0.1em} 7 bits (que l'on préfixe en
général par un 0 pour com\-plé\-ter l'octet) les caractères usuels de la langue
anglaise, c'est-à-dire les lettres majuscules et minuscules, les chiffres,
quelques symboles de ponctuation, ainsi que des caractères de contrôle servant
à modifier le comportement des terminaux\footnote{Oui, à l'époque, les
ordinateurs étaient quelque peu encombrants, donc les opérateurs disposaient
d'un clavier et d'un écran permettant de les contrôler depuis un bureau.}.
\Cpic{../../../pic/accent.pdf}{UnicodeDecodeError: 'ascii' codec can't decode
byte 0xc3 in position 7: ordinal not in range(128)}
Étant donné que beaucoup de langues utilisent des caractères ne figurant pas
dans \mbox{l'ASCII}, des extensions ont été proposées afin de pallier ce manque.
Une fois de plus, les diverses extensions n'étaient pas toujours compatibles
entre elles, et nous voilà revenus à notre point de départ.
\cpic{../../../pic/xkcd_standards.png}{\copyright XKCD, \url{http://xkcd.com/927}}
Bref, il existe beaucoup de codages possibles pour représenter du texte. Et je
ne parle même pas de le manipuler. Imaginons que vous voulez réécrire un mot en
lettres capitales. Tant qu'il s'agit de caractères ASCII, il suffit d'enlever 32 aux
caractères entre 97 et 122 (les lettres minuscules). Mais comment faire si c'est
une autre lettre ? Ça dépend du codage utilisé. Et rien ne nous garantit que la
capitale correspondante peut elle aussi être représentée. Et puis, qu'est-ce qui
me dit que je ne suis pas en train d'utiliser une lettre différente dessinée de
la même façon ?
\vCpic{../../../pic/pas_un_i.pdf}{U+0399 GREEK CAPITAL LETTER IOTA}
Tous ces problèmes trouvent une solution avec le standard Unicode, qui associe
d'une part un nom à chaque caractère (abstrait), et d'autre part un numéro,
appelé \emph{point de code}. Ainsi, si on connaît la correspondance entre une
convention de codage et les points de code de chacun des caractères, la
manipulation devient plus aisée.
% 'c7 61 20 61 6c 6f 72 73 a0 21 20 4a 65 20 70 65 75 78 20 e9 63 72 69 72 65 20
% 64 65 73 20 63 61 72 61 63 74 e8 72 65 73 20 61 63 63 65 6e 74 75 e9 73 a0 21'
De manière à pouvoir représenter aisément les caractères Unicode, on peut bien
sûr utiliser le codage que l'on veut. Il en existe cependant trois qui ont été
prévus de manière à faciliter les choses. Il s'agit d'UTF-8, UTF-16 et UTF-32,
utilisant comme unité de base 8, 16 ou 32 bits (je dis bien unité de base, parce
qu'un caractère peut nécessiter plusieurs unités), et qui peuvent encoder
n'importe quel caractère Unicode.
\section{Et Python dans tout ça ?}
En Python 2.x, il existe deux types de chaînes de caractères : \lstinline{str}
et \lstinline{unicode}. Les deux peuvent servir à représenter des caractères.
Comme vous l'aurez deviné, \lstinline{unicode} sert à représenter des chaînes de
caractères Unicode. Par opposition, comme son nom ne l'indique pas,
\lstinline{str} devrait servir à représenter des suites d'octets, dont certaines
sont, de manière fortuite, des représentations encodées d'une chaîne de
caractères. En Python 3, la notation est clarifiée puisque les chaînes Unicode
sont rebaptisées \lstinline{str}, alors que les suites d'octets prennent le type
\lstinline{bytes}.
\begin{center}
\begin{tabular}{r@{}cc|ccccc}
& Python 2 & Python 3 & \greektext σ & \greektext o & \greektext f & \greektext 'i & \greektext a \\
\hline
\tikz[remember picture] \node (n1) {}; & \lstinline{unicode} & \lstinline{str} & 03C3 & 03BF & 03C6 & 03AF & 03B1 \tikz[remember picture] \node (n3) {};\\
\tikz[remember picture] \node (n2) {}; & \lstinline{str} & \lstinline{bytes} & CF83 & CEBF & CF86 & CEAF & CEB1 \tikz[remember picture] \node (n4) {};\\
\end{tabular}\\*[.5ex]
Un exemple en UTF-8
\begin{tikzpicture}[remember picture, overlay, >=stealth]
\path[->] (n1.west) edge[bend right] node[midway, left] {\lstinline{.encode("utf-8")}} (n2.west);
\path[->] (n4.east) edge[bend right] node[midway, right] {\lstinline{.decode("utf-8")}} (n3.east);
\end{tikzpicture}
\end{center}
En pratique, pour passer d'une chaîne d'octets à une chaîne Unicode, il faut
utiliser la méthode \lstinline{decode}, qui prend en argument le nom du codage
utilisé (et aussi la manière de traiter les erreurs, je vous laisse lire la
documentation si ça vous intéresse). Le passage d'une chaîne Unicode à une
chaîne d'octets se fait via la méthode \lstinline{encode} qui fonctionne de la
même façon.
\begin{lstlisting}
b = "\xc3\xa9" # un "é" en UTF-8
s = b.decode("utf-8") # un "é" représenté en Unicode (U+00E9)
S = s.upper() # un "É" représenté en Unicode (U+00C9)
B = S.encode("utf-8") # un "É" en UTF-8 (C389)
\end{lstlisting}
Lorsqu'on veut représenter du texte, il est donc fortement recommandé d'utiliser
des chaînes Unicode le plus longtemps possible, et de ne choisir un encodage que
pour importer ou exporter le texte (dans un fichier ou via un réseau, par
exemple). Que ce soit pour du texte ou des suites d'octets, il est primordial de
bien savoir ce que l'on manipule afin d'éviter les confusions. Surtout en
Python 2 où le passage entre \lstinline{str} et \lstinline{unicode} peut être
implicite (et source d'erreurs cryptiques et difficiles à repérer).
\cpic{../../../pic/sandwich.pdf}{Le \og sandwich unicode \fg}
\subsection{Mauvaises pratiques}
\begin{enumerate}
\item Une fonction \og universelle \fg{} de conversion (Python 2.x, a son
équivalent en Python 3.x)
\begin{lstlisting}
def convert_everything_to_unicode(x):
if isinstance(x, unicode):
return x
else:
return str(x).decode('utf-8')
\end{lstlisting}
Cette fonction n'est pas fondamentalement mauvaise, puisqu'elle sert à
convertir une chaîne d'octets en chaîne Unicode. Cependant, elle n'aide
en rien à connaître le contenu de \lstinline{x}, et donc devient dangereuse
si utilisée n'importe où. De plus, elle présuppose que la chaîne
d'octets encode un texte en UTF-8, ce qui n'est pas né\-ces\-sai\-re\-ment le
cas (sauf convention d'usage, qui doit dans ce cas être clairement
explicitée). Enfin, elle opère une conversion en chaîne d'octets, ce qui
ouvre la porte à beaucoup de mauvaises utilisations. Même remarque pour
la fonction inverse :
\begin{lstlisting}
def convert_everything_to_str(x):
if isinstance(x, str):
return x
else:
return unicode(x).encode('utf-8')
\end{lstlisting}
\item Mélanger \lstinline{str} et \lstinline{unicode} (Python 2.x
uniquement)
\begin{lstlisting}
def print_result(r):
print u"Résultat : " + str(r)
\end{lstlisting}
Cette fonction présente deux points de danger : premièrement,
l'opérateur \lstinline{+} opéré entre un \lstinline{str} et un
\lstinline{unicode}, qui entraîne une conversion implicite du
\lstinline{str} en \lstinline{unicode}. Si par malheur,
\lstinline{str(r)} renvoie une chaîne d'octets contenant des octets de
valeur numérique supérieure à 127, une erreur serait lancée :
\begin{lstlisting}[language=PythonError]
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 0: ordinal not in range(128)
\end{lstlisting}
Deuxièmement, l'erreur inverse risque de se produire si l'encodage de la
chaîne Unicode demandé implicitement par \lstinline{print} échoue
(souvent parce que l'encodage de la sortie standard n'est pas connu ou
est plus restrictif que nécessaire) :
\begin{lstlisting}[language=PythonError]
UnicodeEncodeError: 'ascii' codec can't encode character u'\xe9' in position 0: ordinal not in range(128)
\end{lstlisting}
Ces problèmes sont résolus en Python 3.x, où aucune conversion entre
\lstinline{bytes} et \lstinline{str} n'est faite implicitement. On a
donc une erreur lorsqu'on essaie par exemple de concaténer une chaîne
d'octets et une chaîne de caractères Unicode, quel que soit le contenu
des chaînes.
\end{enumerate}
\subsection{Quelques conseils}
\begin{enumerate}
\item Fichiers texte
En Python 2.x, on peut manipuler des fichiers texte à l'aide du module
\lstinline{codecs} qui permet de spécifier un codage lors de l'ouverture
du fichier :
\begin{lstlisting}
import codecs
with codecs.open("toto.txt", "w", encoding="utf-8") as f:
f.write(u"Enchant\u00e9.\n")
\end{lstlisting}
Attention cependant, en utilisant le module \lstinline{codecs}, on perd
la conversion automatique des fins de ligne.
En Python 3.x, la fonction \lstinline{open} dispose d'un argument
\lstinline{encoding} qui permet d'utiliser directement ce que permettait
\lstinline{codecs.open} en Python 2.x. On peut également noter que les
retours à la ligne peuvent être convertis automatiquement, contrairement
aux fichiers ouverts avec le module \lstinline{codecs}.
\begin{lstlisting}
with open("toto.txt", "w", encoding="utf-8") as f:
f.write("Enchant\u00e9.\n")
\end{lstlisting}
\item Déclarez un codage si possible
Pour de nombreux dispositifs d'entrée-sortie, il est possible de
déclarer un encodage :
\begin{lstlisting}
# -*- coding: cp1252 -*-
\end{lstlisting}
\begin{lstlisting}[language=xml]
<?xml version="1.0" encoding="iso-8859-1"?>
\end{lstlisting}
\begin{lstlisting}[language=html]
<meta http-equiv="Content-Type"
content="text/html;charset=utf-8"?>
\end{lstlisting}
Si vous utilisez un codage fixe, n'oubliez pas de préciser la convention
dans la documentation de votre code.
Attention cependant, vous ne devez (et ne pouvez) pas faire confiance
aux données venant de l'extérieur. Il se peut très bien que le codage
annoncé ne permette pas de décoder l'entrée correspondante.
\begin{lstlisting}
data_raw="""
<?xml version="1.0" encoding="utf-8"?>
<junk>\xff\x00\x11\x22</junk>
"""
data = data_raw.decode("utf-8")
\end{lstlisting}
\begin{lstlisting}[language=PythonError]
UnicodeDecodeError: 'utf8' codec can't decode byte 0xff in position 46: invalid start byte
\end{lstlisting}
N'essayez pas pour autant de deviner l'encodage à utiliser. Prévoyez
simplement l'éventualité de manière à ce que l'exception levée ne
perturbe pas le comportement de votre code.
\end{enumerate}
\section{Conclusion}
Maintenant que vous avez les bases, il ne vous reste qu'à voler de vos propres
ailes. Comme partout, c'est en essayant et en faisant des erreurs qu'on apprend.
Et surtout, \emph{testez votre code} avec des entrées volontairement
pathologiques (UTF-8 non valide, codage annoncé différent du codage réel,
caractères non-ASCII, caractères multi-octets, etc.).
Un lien utile, qui a grandement inspiré cet article :
\url{http://nedbatchelder.com/text/unipain.html}
\end{document}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment