Comment puis-je lire en UTF-8 avec le diamant de l'opérateur (<>)?
Je veux lire UTF-8 entrée en Perl, peu importe si il s'agit de l'entrée standard ou à partir d'un fichier, à l'aide de l'opérateur diamant: while(<>){...}
.
Donc mon script doit être appelée dans ces deux voies, comme d'habitude, en donnant le même résultat:
./script.pl utf8.txt
cat utf8.txt | ./script.pl
Mais les sorties diffèrent! Seulement le deuxième appel (à l'aide de cat
) semble fonctionner comme prévu, la lecture correctement l'UTF-8. Voici le script:
#!/usr/bin/perl -w
binmode STDIN, ':utf8';
binmode STDOUT, ':utf8';
while(<>){
my @chars = split //, $_;
print "$_\n" foreach(@chars);
}
Comment puis-je faire lire UTF-8 correctement dans les deux cas? Je voudrais continuer à utiliser le diamant de l'opérateur <>
pour la lecture, si possible.
EDIT:
J'ai réalisé que je devrais probablement décrire les différentes sorties. Mon fichier d'entrée contient cette séquence: a\xCA\xA7b
. La méthode avec cat
correctement les résultats:
a
\xCA\xA7
b
Mais l'autre méthode me donne ceci:
a
\xC3\x8A
\xC2\xA7
b
Vous devez vous connecter pour publier un commentaire.
Essayez d'utiliser le pragma s'ouvre à la place:
Vous avez besoin de faire cela parce que le <> opérateur est magique. Comme vous le savez, il va lire depuis l'entrée standard ou à partir des fichiers de @ARGV. La lecture de l'entrée standard STDIN ne pose pas de problème comme STDIN est déjà ouvert donc binmode fonctionne bien sur il. Le problème est lors de la lecture à partir des fichiers de @ARGV, lorsque votre script démarre et appels binmode les fichiers ne sont pas ouverts. Cela provoque STDIN pour être mis en UTF-8, mais ce IO canal n'est pas utilisé lors de l' @ARGV a fichiers. Dans ce cas, le <> opérateur ouvre un nouveau descripteur de fichier pour chaque fichier @ARGV. Chaque descripteur de fichier est remis et perd c'est de l'UTF-8 attribut. En utilisant le pragma vous ouvrir de force chaque nouvelle STDIN pour être en UTF-8.
Votre script fonctionne si vous faites cela:
La magie descripteur de fichier que <> lit s'appelle
*ARGV
, et il estouvert lorsque vous appelez readline.
Mais vraiment, je suis un fan de l'utilisation explicite
Encode::decode
etEncode::encode
le cas échéant.binmode
après la première ligne a déjà été lu par<>
". Cependant, je l'ai essayé, et t de travail. Très magique.Vous pouvez basculer sur l'UTF8 par défaut avec le
-C
drapeau:Le commutateur
-CSD
s'allume UTF8 sans condition; si vous utilisez simplement-C
il s'allume UTF8 que si les variables d'environnement (LC_ALL
,LC_TYPE
etLANG
) de l'indiquer. Voir perlrun pour plus de détails.Ce n'est pas recommandé si vous n'avez pas invoquer perl directement (en particulier, il pourrait ne pas fonctionner de manière fiable si vous passer des options à perl à partir de la ligne shebang). Voir les autres réponses dans ce cas.
#!/usr/bin/env
truc. Ces jours, vous peut généralement supposer queperl
est installé dans/usr/bin
. Voir ma réponse cette question sur Unix & Linux pour plus de détails.Si vous mettez un appel à binmode à l'intérieur de la boucle while, alors il va changer le descripteur de l'utf8 mode APRÈS la première ligne est lu. Ce n'est probablement pas ce que vous voulez faire.
Quelque chose comme ce qui suit pourrait fonctionner mieux:
L'appel à la fonction eof() avec parens est magique, comme il vérifie à la fin du fichier sur le pseudo-descripteur de fichier utilisé par <>. Il sera, si nécessaire, ouvrez la poignée suivante qui doit être lu, ce qui a généralement pour effet de rendre *ARGV valide, mais sans lire quoi que ce soit. Cela nous permet de binmode le premier fichier qui est lu à partir, avant que les choses lues.
Plus tard, eof (sans les parenthèses) est utilisé; ceci permet de vérifier la dernière manche qui a été lu à partir de la fin du fichier. Elle sera fidèle après, nous avons procédé de la dernière ligne de chaque fichier à partir de la ligne de commande (ou lors de l'entrée standard stdin atteint sa fin).
Évidemment, si nous avons juste transformé la dernière ligne d'un fichier, l'appel de la fonction eof() (avec les parenthèses) ouvre le fichier suivant (si il y en a un), rend *ARGV valide (si elle le peut), et les tests de fin de fichier sur le fichier suivant. Si le prochain fichier est présent, et n'est pas à la fin du fichier, puis nous pouvons utiliser binmode sur ARGV.