tr ne remplace pas apostrophe

Je veux convertir toutes les apostrophes dans ce file en X :

 Bob's book Bob's book Bob′s book # (Might look the same but actually different) 

La première apostrophe est remplacée comme prévu:

 $ cat file | tr "'" "X" BobXs book Bob's book Bob′s book 

Mais les deux autres sortes d'apostrophe, des choses étranges se produisent:

 $ cat file | tr "'" "X" Bob's book BobXXXs book BobXX s book $ cat file | tr "′" "X" Bob's book BobXX s book BobXXXs book 

Comment le faire fonctionner?

tr fonctionne en unités d'octets, ce qui signifie qu'il ne fonctionne pas correctement pour les encodings multi-octets comme UTF-8. Les seules solutions que je connaisse sont de find une version de tr qui supporte Unicode, ou de passer à sed ou un autre outil qui peut faire le rlocation de string.

Pour moi, tr fonctionne bien pour les files ascii et utf-8 aussi longtime que votre operating system est configuré pour fonctionner avec la page de codes utf-8.

Voici mon exemple # 1 (Solaris 11):

 $ locale LANG=en_US.UTF-8 LC_CTYPE="en_US.UTF-8" LC_NUMERIC="en_US.UTF-8" LC_TIME="en_US.UTF-8" LC_COLLATE="en_US.UTF-8" LC_MONETARY="en_US.UTF-8" LC_MESSAGES="en_US.UTF-8" LC_ALL= 

Comme vous pouvez le voir, OS est configuré pour fonctionner avec utf-8. J'ai créé les deux files dans la page de code utf-8:

 $ cat file Bob's Bob′s Bob's $ cat apos '′' 

Ensuite, j'ai obtenu des résultats qui remplacent tous les apos comme ceci:

 $ cat file | tr "$(cat apos)" "xxx" Bobxs Bobxs Bobxs 

Voici mon exemple # 2 (Solaris 10):

 $ locale LANG= LC_CTYPE="C" LC_NUMERIC="C" LC_TIME="C" LC_COLLATE="C" LC_MONETARY="C" LC_MESSAGES="C" LC_ALL= 

Ici vous pouvez voir que cet OS est configuré pour gérer ASCII simple, pas utf-8, donc vous pouvez s'attendre à des problèmes de traitement des files utf-8 avec des caractères multi-octets en utilisant tr. Mais il y a une solution de contournement. Comme la command tr permet de saisir la représentation octale du caractère, vous pouvez replace tous les octets du caractère spécifié par la représentation octale.

Dans votre cas, vous avez:

 char hex octal ' E2 80 99 \342\200\231 ′ E2 80 B2 \342\200\262 ' 27 \47 

Firts et second apos sont représentés par trois octets. Le troisième est l'ascii standard (un octet).

Donc, si vous voulez replace les premières apos vous pouvez utiliser:

 $ cat file | tr "\342\200\231" "\0\0x" Bobxs Bob▒s Bob's 

Seconde:

 $ cat file | tr "\342\200\262" "\0\0x" Bob▒s Bobxs Bob's 

Troisième:

 $ cat file | tr "\47" "x" Bob's Bob′s Bobxs 

Pour replace tout en un coup, vous pouvez utiliser:

 $ cat file | tr "\342\200\231\262\47" "\0\0xxx" Bobxs Bobxs Bobxs 

Bien sûr, ce n'est pas parfait tant que cela replacea toutes les occurrences de byte \ 342, \ 200, \ 231, \ 262 dans le file, donc d'autres caractères multi-octets contenant ces octets seront cassés. Mais si votre file ne contient pas d'autres caractères multi-octets, cela fonctionnera.