Como converter esta string para o japonês usando ferramentas GNU / Linux?

2

Aqui está uma string de um arquivo de texto:

@™TdaŽ®Æ‚êƒ~ƒNƒXƒgƒŒ[ƒgEƒrƒLƒjver1.11d1.d2iƒrƒLƒjƒ‚ƒfƒ‹ver.1.1³Ž®”z•z”Åj

Ele inclui muitos caracteres não imprimíveis e é copiado aqui: link

Ao usar o link , podemos confirmar que ele se traduz para o seguinte:

 ☆Tda式照れミクストレート・ビキニver1.11d1.d2(ビキニモデルver.1.1正式配布版)

Isto é com codificação de origem = SJIS (shift-jis), exibido como Windows-1252.

Mas como podemos obter o mesmo resultado sem um site? A ferramenta relevante é iconv, mas algo na cadeia de ferramentas está quebrado. Se eu tentar catar o arquivo de texto de origem ou usá-lo como entrada padrão com '<' no bash, um dos 'iconv's na cadeia rapidamente comete erros. Se eu copiar a string acima do editor de texto gedit (lendo o arquivo como utf-16le) ou como saída por iconv com a conversão utf16-to-utf8, então o resultado é próximo, mas ainda assim errado:

@儺da式ニれミクストレ[トEビキニver1.11d1.d2iビキニモデルver.1.1ウ式配布版j

Algumas evidências da falha da cadeia de ferramentas:

$ cat 'utf8.txt' |head -1

@™TdaŽ®Æ‚êƒ~ƒNƒXƒgƒŒ[ƒgEƒrƒLƒjver1.11d1.d2iƒrƒLƒjƒ‚ƒfƒ‹ver.1.1³Ž®”z•z”Å

$ cat 'utf8.txt' |head -1| iconv -f utf8 -t utf16

���@�"!Tda}��� ��~�N�X�g�R�[�g�E�r�L�jver1.11d1.d2�i�r�L�j� �f�9 ver.1.1��}� z" z ��j

Observe três caracteres inválidos no início.

$ cat 'utf8.txt' |head -1| iconv -f utf8 -t utf16|iconv -f utf16 -t windows-1252

iconv: illegal input sequence at position 2

$ echo "@™TdaŽ®Æ‚êƒ~ƒNƒXƒgƒŒ[ƒgEƒrƒLƒjver1.11d1.d2iƒrƒLƒjƒ‚ƒfƒ‹ver.1.1³Ž®”z•z”Åj"| iconv -f utf8 -t utf16

��@"!Tda}�� ��~�N�X�g�R[�gE�r�L�jver1.11d1.d2i�r�L�j� �f�9 ver.1.1�}� z" z �j

Observe dois caracteres inválidos no início, outras diferenças. A seqüência copiada do terminal corresponde à string exibida no editor de texto, confirmada por find (ctrl-F) correspondente a ela, que é a mesma string que fornece o resultado correto em 2cyr.com.

Estendendo o último comando acima com '| iconv -f utf16 -t windows-1252 | iconv -f shift-jis -t utf8' mostra o resultado próximo, mas incorreto, citado acima, ao invés de errar como a cadeia direta faz .

Se eu tentasse criar um arquivo chamado string de exemplo e usar a ferramenta convmv nele, convmv disse que o nome do arquivo de saída continha "caracteres, que não são compatíveis com o sistema de arquivos POSIX! Isso pode resultar em perda de dados." A maioria dos nomes de arquivos inválidos com o UTF-8 não fornecem esse aviso.

Existe alguma seqüência de bits que a tubulação no bash não pode manipular? Se não, por que a cadeia de ferramentas não está funcionando?

Aparentemente, a diferença é porque o bash não colará caracteres não impressos (as caixas com números) na linha de comando; talvez 'readline' não possa lidar com eles? Mas o resultado sendo próximo sugere que a ordem de conversão no conjunto de ferramentas está correta, então por que não está funcionando?

O arquivo original, com seu nome de arquivo embaralhado de uma maneira diferente (expira após 30 dias): link

    
por Misaki 30.03.2018 / 13:11

1 resposta

3

Pipes são um recurso do sistema operacional que funciona com buffers de bytes e não interpreta o conteúdo de forma alguma. Então o texto canalizado não passa por bash e especialmente nunca através de 'readline'. Texto colado como argumentos de linha de comando. (E sim, tanto o readline quanto o terminal podem filtrar caracteres de controle como medida de segurança.)

Seu arquivo é, na verdade, uma mistura de duas codificações, windows-1252 e iso8859-1 , devido às diferentes maneiras de usar o bloco de caracteres de controle C1 (0x80..0x9F).

  • A ISO 8859-1 usa esse intervalo inteiro para caracteres de controle e os bytes 0x80..0x9F correspondem aos pontos de código Unicode U + 0080..U + 009F.
  • O Windows-1252 não pode representar caracteres de controle C1; ele usa a maior parte desse intervalo para caracteres imprimíveis e possui alguns "buracos" - isto é, valores de bytes que não têm nada atribuído (0x81, 0x8D, 0x8F, 0x90, 0x9D).
  • As duas codificações são idênticas nos intervalos 0x00..0x7F e 0xA0..0xFF.

Vamos pegar a primeira linha do seu arquivo de entrada "ruim", decodificado de UTF-16 para texto Unicode e com caracteres não-imprimíveis que escaparam:

\u0081@\u0081™TdaŽ®\u008FÆ‚êƒ~ƒNƒXƒgƒŒ\u0081[ƒg\u0081EƒrƒLƒjver1.11d1.d2\u0081iƒrƒLƒjƒ‚ƒfƒ‹ver.1.1\u0090³Ž®”z•z”Å\u0081j\n
  • Você pode ver \u0081 (U + 0081), que é mapeado para o byte 0x81 na ISO 8859-1, mas não pode ser codificado no Windows-1252.
  • Você também pode ver o símbolo ƒ (U + 0192), que é mapeado para 0x83 no Windows-1252, mas não existe na ISO 8859-1.

Assim, o truque é usar o Windows-1252 quando possível e a ISO 8859-1 como substituto, decidindo individualmente para cada ponto de código. (libiconv poderia fazer isso via 'ICONV_SET_FALLBACKS', mas a ferramenta CLI iconv não pode.) É fácil escrever sua própria ferramenta:

#!/usr/bin/env python3
with open("/dev/stdin", "rb") as infd:
    with open("/dev/stdout", "wb") as outfd:
        for rune in infd.read().decode("utf-16"):
            try:
                chr = rune.encode("windows-1252")
            except UnicodeEncodeError:
                chr = rune.encode("iso8859-1")
            outfd.write(chr)
            # outputs shift-jis

Note que apenas metade do seu arquivo de entrada é codificado incorretamente como Shift-JIS. A outra metade (em inglês) é perfeitamente boa UTF-16; felizmente, o Shift-JIS passará por isso, então não é necessário dividir manualmente:

#!/usr/bin/env python3
with open("éΦé╟é▌üEé╓é╚é┐éσé▒éªéΦé⌐.txt", "r", encoding="utf-16") as infd:
    with open("りどみ・へなちょこえりか.txt", "w", encoding="utf-8") as outfd:
        buf = b""
        for rune in infd.read():
            try:
                buf += rune.encode("windows-1252")
            except UnicodeEncodeError:
                try:
                    buf += rune.encode("iso8859-1")
                except UnicodeEncodeError:
                    buf += rune.encode("shift-jis")
        outfd.write(buf.decode("shift-jis"))
    
por 30.03.2018 / 16:23