web-dev-qa-db-fra.com

Convertir UTF8 en UTF16 en utilisant iconv

Lorsque j'utilise iconv pour convertir de UTF16 en UTF8, tout va bien, mais vice versa, cela ne fonctionne pas. J'ai ces fichiers:

a-16.strings:    Little-endian UTF-16 Unicode c program text
a-8.strings:     UTF-8 Unicode c program text, with very long lines

Le texte semble OK dans l'éditeur. Quand je lance ceci:

iconv -f UTF-8 -t UTF-16LE a-8.strings > b-16.strings

Ensuite, j'obtiens ce résultat:

b-16.strings:    data
a-16.strings:    Little-endian UTF-16 Unicode c program text
a-8.strings:     UTF-8 Unicode c program text, with very long lines

L'utilitaire file n'affiche pas le format de fichier attendu et le texte ne semble pas non plus bien dans l'éditeur. Se pourrait-il que iconv ne crée pas une nomenclature appropriée? Je l'exécute sur la ligne de commande MAC.

Pourquoi le b-16 n'est-il pas au bon format UTF-16LE? Existe-t-il une autre façon de convertir utf8 en utf16?

Plus d'élaboration se trouve ci-dessous.

$ iconv -f UTF-8 -t UTF-16LE a-8.strings > b-16le-BAD-fromUTF8.strings
$ iconv -f UTF-8 -t UTF-16 a-8.strings > b-16be.strings 
$ iconv -f UTF-16 -t UTF-16LE b-16be.strings > b-16le-BAD-fromUTF16BE.strings

$ file *s
a-16.strings:                   Little-endian UTF-16 Unicode c program text, with very long lines
a-8.strings:                    UTF-8 Unicode c program text, with very long lines
b-16be.strings:                 Big-endian UTF-16 Unicode c program text, with very long lines
b-16le-BAD-fromUTF16BE.strings: data
b-16le-BAD-fromUTF8.strings:    data


$ od -c a-16.strings | head
0000000  377 376   /  \0   *  \0      \0  \f 001   E  \0   S  \0   K  \0

$ od -c a-8.strings | head 
0000000    /   *   *   *       Č  **   E   S   K   Y       (   J   V   O

$ od -c b-16be.strings | head
0000000  376 377  \0   /  \0   *  \0   *  \0   *  \0     001  \f  \0   E

$ od -c b-16le-BAD-fromUTF16BE.strings | head                                
0000000    /  \0   *  \0   *  \0   *  \0      \0  \f 001   E  \0   S  \0

$ od -c b-16le-BAD-fromUTF8.strings | head
0000000    /  \0   *  \0   *  \0   *  \0      \0  \f 001   E  \0   S  \0

Il est clair que la nomenclature est manquante chaque fois que j'exécute la conversion en UTF-16LE. Une aide à ce sujet?

26

UTF-16LE indique à iconv de générer un UTF-16 petit-boutien sans une nomenclature (Byte Order Mark). Apparemment, cela suppose que puisque vous avez spécifié LE, la nomenclature n'est pas nécessaire.

UTF-16 lui dit de générer du texte UTF-16 (dans l'ordre des octets de la machine locale) avec une nomenclature.

Si vous êtes sur une petite machine endian, je ne vois pas de moyen de dire à iconv de générer un UTF-16 big-endian avec une nomenclature, mais il se peut que je manque quelque chose.

Je trouve que la commande file ne reconnaît pas le texte UTF-16 sans nomenclature, et votre éditeur ne le peut pas non plus. Mais si vous exécutez iconv -f UTF-16LE -t UTF_8 b-16 strings, vous devriez obtenir une version UTF-8 valide du fichier d'origine.

Essayez d'exécuter od -c sur les fichiers pour voir leur contenu réel.

MISE À JOUR:

Il semble que vous soyez sur une machine big-endian (x86 est little-endian) et que vous essayez de générer un fichier UTF-16 little-endian avec une nomenclature. Est-ce exact? Pour autant que je sache, iconv ne le fera pas directement. Mais cela devrait fonctionner:

( printf "\xff\xfe" ; iconv -f utf-8 -t utf-16le UTF-8-FILE ) > UTF-16-FILE

Le comportement de printf peut dépendre de vos paramètres régionaux; J'ai LANG=en_US.UTF-8.

(Quelqu'un peut-il suggérer une solution plus élégante?)

Une autre solution de contournement, si vous connaissez l'endianité de la sortie produite par -t utf-16:

iconv -f utf-8 -t utf-16 UTF-8-FILE | dd conv=swab 2>/dev/null
36
Keith Thompson

Je me convertis d'abord en UTF-16, qui ajoutera une marque d'ordre d'octets, si nécessaire comme Keith Thompson le mentionne . Puis depuis UTF-16 ne définit pas l'endianité, nous devons utiliser file pour déterminer si c'est UTF-16BE ou UTF-16LE. Enfin, nous pouvons convertir en UTF-16LE.

iconv -f utf-8 -t utf-16 UTF-8-FILE > UTF-16-UNKNOWN-ENDIANNESS-FILE
FILE_ENCODING="$( file --brief --mime-encoding UTF-16-UNKNOWN-ENDIANNESS-FILE )"
iconv -f "$FILE_ENCODING" -t UTF-16LE UTF-16-UNKNOWN-ENDIANNESS-FILE > UTF-16-FILE
3
Heath Borders

Ce n'est peut-être pas une solution élégante, mais j'ai trouvé un moyen manuel d'assurer une conversion correcte de mon problème qui, je pense, est similaire au sujet de ce fil.

Le problème: J'ai obtenu un fichier de données texte d'un utilisateur et j'allais le traiter sur Linux (spécifiquement, Ubuntu) en utilisant le script Shell (tokenisation, fractionnement, etc.). Appelons le fichier myfile.txt. La première indication que j'ai compris que quelque chose n'allait pas était que la tokenisation ne fonctionnait pas. Je n'ai donc pas été surpris lorsque j'ai exécuté la commande file sur myfile.txt et a obtenu ce qui suit

$ file myfile.txt

myfile.txt: Little-endian UTF-16 Unicode text, with very long lines, with CRLF line terminators

Si le fichier était conforme, voici ce qui aurait dû être la conversation:

$ file myfile.txt

myfile.txt: ASCII text, with very long lines

La solution: Pour rendre le fichier de données conforme, voici les 3 étapes manuelles que j'ai trouvées fonctionner après quelques essais et erreurs avec d'autres étapes.

  1. Convertissez d'abord en Big Endian avec le même encodage via vi (ou vim). vi myfile.txt. Dans vi do :set fileencoding=UTF-16BE puis écrivez le fichier. Vous devrez peut-être le forcer avec :!wq.

  2. vi myfile.txt (qui devrait maintenant être dans utf-16BE). Dans vi do :set fileencoding=ASCII puis écrivez le fichier. Encore une fois, vous devrez peut-être forcer l'écriture avec !wq.

  3. Courir dos2unix convertisseur: d2u myfile.txt. Si vous exécutez maintenant file myfile.txt vous devriez maintenant voir une sortie ou quelque chose de plus familier et rassurant comme:

    myfile.txt: ASCII text, with very long lines
    

C'est ça. C'est ce qui a fonctionné pour moi, et j'ai ensuite pu exécuter mon script shell de traitement bash de myfile.txt. J'ai trouvé que je ne peux pas sauter l'étape 2. Autrement dit, dans ce cas, je ne peux pas passer directement à l'étape 3. J'espère que vous trouverez ces informations utiles; j'espère que quelqu'un pourra l'automatiser peut-être via sed ou similaire. À votre santé.

0
Adams