2016-08-23 6 views
0

私はドイツ人ですから、äöüのようなウムラウトを使用しています。 Golangはstdinから正しく読まない。 Golang stdinはドイツのウムラウトを間違って読みます

package main 

import (
    "bufio" 
    "fmt" 
    "os" 
) 

func main() { 
    for { 
     b, _, _ := bufio.NewReader(os.Stdin).ReadLine() 
     printBytes(b) 
    } 

} 

func printBytes(bytes []byte) { 
    for _, b := range bytes { 
     fmt.Printf("0x%X ", b) 
    } 
    fmt.Println() 
} 

が、私は出力を得る:私はこの単純なプログラム実行

C:\dev\golang>go run test.go 
ä 
0xE2 0x80 0x9E 

E2 80 9EはUTF-8でäの正しいバイトシーケンス(this toolではありませんが、それはです私に語りました"DOUBLE LOW-9 QUOTATION MARK" - >)、私が読んだことだけを印刷すると、"が印刷されます。

package main 

/* 
#include <stdio.h> 
#include <stdlib.h> 

char * getline(void) { 
    char * line = malloc(100), * linep = line; 
    size_t lenmax = 100, len = lenmax; 
    int c; 

    if(line == NULL) 
     return NULL; 

    for(;;) { 
     c = fgetc(stdin); 
     if(c == EOF) 
      break; 

     if(--len == 0) { 
      len = lenmax; 
      char * linen = realloc(linep, lenmax *= 2); 

      if(linen == NULL) { 
       free(linep); 
       return NULL; 
      } 
      line = linen + (line - linep); 
      linep = linen; 
     } 

     if((*line++ = c) == '\n') 
      break; 
    } 
    *line = '\0'; 
    return linep; 
} 

void freeline(char* ptr) { 
    free(ptr); 
} 
*/ 
import "C" 

import (
    "fmt" 
    "golang.org/x/text/encoding/charmap" 
) 

func getLineFromCp850() string { 
    line := C.getline() 
    goline := C.GoString(line) 
    C.freeline(line) 
    b := []byte(goline) 
    ub, _ := charmap.CodePage850.NewDecoder().Bytes(b) 
    return string(ub) 
} 

func main() { 
    for { 
     line := getLineFromCp850() 
     printBytes([]byte(line)) 
    } 

} 

func printBytes(bytes []byte) { 
    for _, b := range bytes { 
     fmt.Printf("0x%X ", b) 
    } 
    fmt.Println() 
} 

そして、それは出て印刷します:私は小さな修正文字を読むように思われた「ハック」を書いた

C:\dev\golang>go run test.go 
ä 
0xC3 0xA4 0xA 

C3 A4äの正しいbytesequenceです(0Aがどの改行ですCP850からUTF-8への読み込みと変換は私の予想どおりですが、cgoの代わりにGoの機能を使って行を読んだとき、なぜ私は不安を感じますか? Goで何が問題なのですか?CP850として入力バイトを解釈するのではなく、別の文字セットを解釈しませんか?この問題を処理するためのより良いGo専用の方法はありますか?

をstdinから読み込んだときにのみこの問題が発生します。私がUTF-8 äをstdoutに出力すると、コンソールに正しく印刷されます。

+1

あなた自身の質問に答えられませんでしたか? GoはデフォルトでUTF8を仮定していますが、CP850を入力しています – JimB

+0

Goはソースコード内の文字列に対してUTF-8を仮定していますが、端末(cmd.exe)から実行すると、stdinを正しく読み込んで端末のコードページUTF-8?もしGoがUTF-8をコンソールから期待していたとしても、これはなぜ私が完全に無関係なUTF-8文字を得るのかを説明するものではなく、エラー・ルーンだけではありません。私がstdinから直接バイトを読み込んだとしても、私のC関数が 'ä 'のCP850の値を正しく受け取るので、コンソール__definitely__は送信しません。 – tkausl

+0

コンソールが850を使用していても、Golangは入力を850ではなくコードページ1252と解釈するので、[私は問題を作成しました](https://github.com/golang/go/issues/16857) – tkausl

答えて

0

これは、いくつかのシステムで、全体的に使用される文字セットとコンソール文字セットが異なるWindowsシステム(WinAPIのGetACP()GetConsoleCP()が異なるものを返す)に特有のバグでした。例えばドイツ(西ヨーロッパ諸国など)では、Windowsはコードセット1252を全体文字セットとして使用しますが、コンソールのコードページ850を使用します(cmd.exe)。理由は分かりませんが、それはどういうものなのでしょうか。 GolangはGetACP()を誤って使用して、GetConsoleCP()によって返されたコードページを実際に使用していたはずのときに、UTF-8への入力をデコードしました。私が作成したIssueの問題が見つかりました.Golangの次のバージョンで修正がマージされることを願っています。

我々はまた、例えば、Golangは他の問題につながる可能性がある(すなわち、それはCOMBININGダイエレシス̈続く文字aäを読んでいました)分解UTF-8文字に文字をデコードし、Windows上の問題を発見しました分解された文字を印刷すると、1つの結合文字ではなく別々の文字が印刷されます。