3 votes

Comment remplacer correctement les caractères ISO-8859-1 par des caractères UTF-8 ?

Je souhaite remplacer les caractères ISO-8859-1 du fichier ci-dessous pour qu'ils soient valides pour l'encodage UTF-8.

<HTML>
<HEAD>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
</HEAD>

<BODY>

<A NAME="top"></A>

<TABLE border=0 width=609 cellspacing=0 cellpadding=0>
<TR><td rowspan=2><img src="http://www.example.com" width=10></td>
<TD width=609 valign=top>

<p>'</p>
<p>*</p>
<p>-</p>
<p>—</p>
<p>§</p>
<p>«</p>
<p>»</p>
<p>¿</p>
<p>Á</p>

</TD>
</TR>
</TABLE>

</body>
</html>

En faisant quelques recherches, j'ai découvert que le problème est lié à locale et j'ai pu construire ce programme awk, mais il ne remplace que les 2 premiers caractères ( ' y * )

LC_ALL=ISO_8859-1 awk '{
   gsub(/charset=iso-8859-1/, "charset=UTF-8"  ,  $0)
   gsub(/\047/, "\\&apos;"  ,  $0)
   gsub(/*/, "\\&ast;"      ,  $0)
   gsub(/–/, "\\&ndash;"    ,  $0)
   gsub(/—/, "\\&mdash;"    ,  $0)
   gsub(/§/, "\\&sect;"     ,  $0)
   gsub(/«/, "\\&laquo;"    ,  $0)
   gsub(/»/, "\\&raquo;"    ,  $0)
   gsub(/¿/, "\\&iquest;"   ,  $0)
   gsub(/Á/, "\\&Aacute;"   ,  $0)
   print
   }' t.html | iconv -f ISO_8859-1 -t UTF-8

Voici la sortie actuelle (ci-dessous une sortie partielle, seules les lignes affectées par le programme) :

<p>&apos;</p>
<p>&ast;</p>
<p>-</p>
<p>-</p>
<p>§</p>
<p>«</p>
<p>»</p>
<p>¿</p>
<p>Á</p>

et le résultat attendu est le suivant :

<p>&ast;</p>
<p>&ndash;</p>
<p>&mdash;</p>
<p>&sect;</p>
<p>&laquo;</p>
<p>&raquo;</p>
<p>&iquest;</p>
<p>&Aacute;</p>

J'ai déjà essayé un code similaire en utilisant sed mais le problème est le même.

Comment résoudre ce problème ?

Ci-dessous la configuration locale :

***Ubuntu 18.04.1 LTS

$ locale
LANG=C.UTF-8
LANGUAGE=
LC_CTYPE="C.UTF-8"
LC_NUMERIC="C.UTF-8"
LC_TIME="C.UTF-8"
LC_COLLATE="C.UTF-8"
LC_MONETARY="C.UTF-8"
LC_MESSAGES="C.UTF-8"
LC_PAPER="C.UTF-8"
LC_NAME="C.UTF-8"
LC_ADDRESS="C.UTF-8"
LC_TELEPHONE="C.UTF-8"
LC_MEASUREMENT="C.UTF-8"
LC_IDENTIFICATION="C.UTF-8"
LC_ALL=

1voto

luciole75w Points 1069

Ce problème est probablement dû à une incompatibilité d'encodage entre le fichier d'entrée et le script awk script.

Notez tout d'abord qu'il y a probablement une confusion (très courante) entre ISO-8859-1 et Windows-1252. L'exemple html dans le post original contient des caractères em/en qui ne font pas partie de la norme ISO-8859-1. ISO-8859-1 mise en page Il utilise donc certainement un autre encodage, probablement Windows-1252 (qui est un surensemble d'ISO-8859-1 incluant les caractères tirets) puisque l'OP a déclaré utiliser Ubuntu à travers la couche du sous-système Windows.

Je supposerai alors que le fichier d'entrée html est effectivement encodé avec Windows-1252. Les caractères non ASCII (points de code 128) n'utilisent donc qu'un seul octet.

Si le programme awk est chargé à partir d'un fichier codé en UTF-8, ou même tapé directement dans une fenêtre de terminal qui utilise le codage UTF-8, les expressions régulières et les chaînes littérales intégrées dans le programme sont également codées en UTF-8. Les caractères non ASCII utilisent donc plusieurs octets.

Par exemple, le caractère § (point de code 167 = 0xA7), est représenté par l'octet A7 dans Windows-1252 et la séquence d'octets C2 A7 en UTF-8. Si vous utilisez gsub(/§/, "S") dans votre programme awk encodé en UTF-8, alors awk recherche la séquence C2 A7 dans le fichier d'entrée qui ne contient que des A7 . Il ne correspondra pas. À moins que vous n'ayez la (mal)chance d'avoir un caractère  (point de code 194 = 0xC2) juste avant que vous n'entriez dans la salle de réunion. § .

Changer la locale n'est pas utile ici car cela indique seulement à awk comment analyser son entrée (données et programme), alors que ce dont vous avez besoin ici est de transcoder soit les données, soit les expressions régulières. Pour que cela fonctionne, il faudrait pouvoir spécifier la locale des données indépendamment de la locale du programme, ce qui n'est pas supporté.

Ainsi, en supposant que votre système est configuré avec une locale UTF-8 et que votre awk script utilise cette locale (qu'il soit chargé depuis un fichier ou tapé dans un terminal), voici plusieurs méthodes que vous pouvez utiliser pour aligner le fichier d'entrée et les expressions régulières sur le même encodage, de sorte que gsub fonctionne comme prévu.

Notez que ces suggestions s'appliquent à votre première commande awk, car c'est elle qui est à l'origine du problème. Le dernier tuyau vers iconv n'est nécessaire que si vous ne transformez pas intentionnellement tous les caractères spéciaux que vous pouvez avoir dans l'entrée en entités html. Dans le cas contraire, la sortie de awk est de l'ASCII pur et simple, donc déjà compatible avec UTF-8.

Option 1 : convertir le fichier d'entrée de Windows-1252 à UTF-8

Pas besoin d'un autre iconv après cela en tout état de cause.

iconv -f WINDOWS-1252 t.html | awk '{
   gsub(/charset=iso-8859-1/, "charset=UTF-8")
   gsub(/\047/, "\\&apos;")
   gsub(/\*/, "\\&ast;")
   gsub(/–/, "\\&ndash;")
   gsub(/—/, "\\&mdash;")
   gsub(/§/, "\\&sect;")
   gsub(/«/, "\\&laquo;")
   gsub(/»/, "\\&raquo;")
   gsub(/¿/, "\\&iquest;")
   gsub(/Á/, "\\&Aacute;")
   print
   }'

Option 2 : convertir le programme awk de UTF-8 à Windows-1252

Parce que le programme awk peut aussi vouloir s'amuser. Utilisons la substitution de processus.

awk -f <(iconv -t WINDOWS-1252 <<'EOS'
{
   gsub(/charset=iso-8859-1/, "charset=UTF-8")
   gsub(/'/, "\\&apos;")
   gsub(/\*/, "\\&ast;")
   gsub(/–/, "\\&ndash;")
   gsub(/—/, "\\&mdash;")
   gsub(/§/, "\\&sect;")
   gsub(/«/, "\\&laquo;")
   gsub(/»/, "\\&raquo;")
   gsub(/¿/, "\\&iquest;")
   gsub(/Á/, "\\&Aacute;")
   print
}
EOS
) t.html

Option 3 : enregistrer l'awk/schell script dans un fichier encodé en Windows-1252

... avec votre outil préféré.

Option 4 : changer l'encodage de votre session de terminal pour Windows-1252

Si vous tapez/collez la commande awk dans un terminal, bien sûr.

Notez que cela diffère de la définition de la locale (LC_CTYPE). Je n'ai pas connaissance d'un moyen de faire cela par programme. Si quelqu'un le sait, n'hésitez pas à contribuer.

Option 5 : éviter les caractères non ASCII dans le programme awk

Il s'agit en tout cas d'une bonne pratique à mon avis.

awk '{
   gsub(/charset=iso-8859-1/, "charset=UTF-8")
   gsub(/\047/, "\\&apos;")
   gsub(/\*/, "\\&ast;")
   gsub(/\226/, "\\&ndash;")
   gsub(/\227/, "\\&mdash;")
   gsub(/\247/, "\\&sect;")
   gsub(/\253/, "\\&laquo;")
   gsub(/\273/, "\\&raquo;")
   gsub(/\277/, "\\&iquest;")
   gsub(/\301/, "\\&Aacute;")
   print
   }' t.html

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X