Caracteres chineses em vez de latim sendo gravados em arquivo

3

Quando executo sed e imprimo em um console, tudo fica bem:

sed '/Q/{
s/Q//g
r /Users/ericbrotto/Desktop/question.txt
}' Commision.txt

Mas quando faço isso e envio um arquivo:

sed '/Q/{
s/Q//g
r /Users/ericbrotto/Desktop/question.txt
}' Commision.txt > newFile

... minha nova string (aquela que foi devidamente substituída na saída anterior) agora é um conjunto de caracteres asiáticos (eu acredito em mandarim).

Alguma idéia?

Este é um problema de acompanhamento para um pergunta que fiz anteriormente .

    
por Eric Brotto 22.07.2011 / 16:54

1 resposta

5

Eu já notei que se você pegar texto codificado em ASCII (ou, equivalentemente, texto ASCII codificado em UTF-8) e decodificá-lo como UTF-16, você frequentemente recebe “caracteres chineses” (diferentes dependendo de decodificá-lo) como UTF-16BE ou UTF-16LE). Com base nisso, acho que você está lidando com codificações mistas. Meu palpite é que Commision.txt é codificado como UTF-16BE ou UTF-16LE, que question.txt é ASCII simples (ou ASCII codificado em UTF-8) e que seu newFile acaba como uma combinação inválida das codificações dos dois arquivos.

As coisas devem funcionar melhor se você usar a mesma codificação em ambos os arquivos; Provavelmente, o UTF-8 funcionará melhor. Se você precisa que a saída final esteja em alguma outra codificação, então você pode usar iconv para convertê-la ( iconv -f UTF-8 -t UTF-16BE <newFile >newfile.utf16be.txt ).

Efetivamente, a codificação UTF-16 de caracteres ASCII é igual à codificação ASCII, mas com caracteres NUL extras inseridos entre cada caractere ASCII junto com mais um NUL antes ou depois de todo o lote (dependendo do endian do UTF- 16 codificação). Isso significa que o texto ASCII codificado como UTF-8 ou UTF-16 parecerá "normal" quando visualizado diretamente em um terminal UTF-8 (ou seja, "imprimir em um console").

Contanto que o conteúdo do arquivo seja mantido separado, qualquer ambiente de visualização de detecção de codificação (por exemplo, um editor) provavelmente detectará corretamente a codificação (ou pelo menos escolherá um que seja suficientemente próximo considerando que UTF-8 e muitos byte único codificações são idênticas na faixa ASCII).

Mas, você tem sed misturando os arquivos juntos. Infelizmente, sed não é “inteligente” o suficiente para perceber que está lidando com arquivos usando duas codificações de texto diferentes. Você acaba com (de acordo com meu palpite) um arquivo que é principalmente codificado em UTF-16 (de Commision.txt ) com uma seção codificada em UTF-8 (de question.txt ) no meio (ou onde quer que seu Q o coloque) ). O resultado é provavelmente inválido se totalmente decodificado como UTF-8, mas possivelmente válido quando totalmente decodificado como UTF-16 (embora com alguns conteúdos inesperados onde os dados UTF-8 são).

Aqui está um exemplo:

Commision.txt é ASCII codificado em UTF-16BE (com uma BOM).

% xxd Commision.txt 
0000000: feff 0046 0069 0072 0073 0074 0020 006c  ...F.i.r.s.t. .l
0000010: 0069 006e 0065 000a 004c 0069 006e 0065  .i.n.e...L.i.n.e
0000020: 0020 0077 0069 0074 0068 0020 0061 0020  . .w.i.t.h. .a. 
0000030: 0075 0063 0020 0027 0071 0027 003a 0020  .u.c. .'.q.'.:. 
0000040: 0028 0051 0029 000a 004c 0061 0073 0074  .(.Q.)...L.a.s.t
0000050: 0020 006c 0069 006e 0065 000a            . .l.i.n.e..

question.txt é ASCII (ou ASCII codificado em UTF-8).

% xxd question.txt
0000000: 5768 6174 2069 7320 7468 6520 6169 722d  What is the air-
0000010: 7370 6565 6420 7665 6c6f 6369 7479 206f  speed velocity o
0000020: 6620 616e 2075 6e6c 6164 656e 2073 7761  f an unladen swa
0000030: 6c6c 6f77 3f0a                           llow?.

Eu os combino com sed .

% sed '/Q/{
s/Q//g
r question.txt
}' Commision.txt >newFile

newFile é uma bagunça.

sed excluiu o Q como um único byte ( 51 ) em vez de sua representação de dois bytes UTF-16 ( 00 51 ).
Isso estraga o alinhamento de dois bytes do restante do arquivo, fornece um comprimento inteiro que é ímpar em vez de igual e introduz um UTF-16 NULL ( 0000 ).

% xxd newFile
0000000: feff 0046 0069 0072 0073 0074 0020 006c  ...F.i.r.s.t. .l
0000010: 0069 006e 0065 000a 004c 0069 006e 0065  .i.n.e...L.i.n.e
0000020: 0020 0077 0069 0074 0068 0020 0061 0020  . .w.i.t.h. .a. 
0000030: 0075 0063 0020 0027 0071 0027 003a 0020  .u.c. .'.q.'.:. 
0000040: 0028 0000 2900 0a57 6861 7420 6973 2074  .(..)..What is t
0000050: 6865 2061 6972 2d73 7065 6564 2076 656c  he air-speed vel
0000060: 6f63 6974 7920 6f66 2061 6e20 756e 6c61  ocity of an unla
0000070: 6465 6e20 7377 616c 6c6f 773f 0a00 4c00  den swallow?..L.
0000080: 6100 7300 7400 2000 6c00 6900 6e00 6500  a.s.t. .l.i.n.e.
0000090: 0a                                       .

Apesar da bagunça, parece bem no meu terminal UTF-8.

% cat newFile
First line
Line with a uc 'q': ()
What is the air-speed velocity of an unladen swallow?
Last line

Quando eu carrego no Vim, no entanto as coisas estão obviamente erradas (na verdade existe um NUL após o parêntese aberto, mas sua presença fez com que este post fosse truncado). Vim avisa "CONVERSION ERROR na linha 2".

First line
Line with a uc 'q': (⤀੗桡琠楳⁴桥⁡楲⵳灥敤⁶敬潣楴礠潦⁡渠畮污摥渠獷慬汯眿਀䰀愀猀琀 氀椀渀攀

Se eu excluir o ponto de interrogação de question.txt (para fornecer um número par de bytes novamente) e gerar novamente newFile , obtenho a última linha "de volta" (embora esteja preso ao final da segunda linha ) e evitar o aviso de conversão do Vim.

First line
Line with a uc 'q': (⤀੗桡琠楳⁴桥⁡楲⵳灥敤⁶敬潣楴礠潦⁡渠畮污摥渠獷慬汯眊Last line
    
por 23.07.2011 / 09:17