Golang stdin看错了德文字母
我来自德国,所以我使用umlauts,比如Golang stdin看错了德文字母,go,character-encoding,Go,Character Encoding,我来自德国,所以我使用umlauts,比如ä,ö和ü。然而,Golang并没有从stdin中正确读取它们 当我执行这个简单的程序时: package main import ( "bufio" "fmt" "os" ) func main() { for { b, _, _ := bufio.NewReader(os.Stdin).ReadLine() printBytes(b) } } func printByte
ä
,ö
和ü
。然而,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中ä
的正确字节序列(告诉我它是一个“双低9引号”->。
),当我刚打印出我读到的内容时,它会打印”
。我写了一个小“hack”,它看起来读的字符是正确的:
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()
}
c3a4
是ä
的正确字节顺序(0A是我的黑客没有剥去的换行符)看起来,从CP850到UTF-8的读取和转换就像我预期的那样,但是当我使用Go的功能而不是cgo来读取行时,为什么Go会给我胡言乱语?Go给我这些值有什么问题,它不是将输入字节解释为CP850而是另一个字符集吗?有更好的Go-only方法来处理这个问题吗有问题吗
这个问题只有在读取stdin时才会出现。当我将UTF-8
ä
打印到stdout时,它会在控制台中正确打印。因此,对于某些系统来说,这是Golang中的一个bug,特别是对于Windows系统,在这些系统中,使用的总字符集和控制台字符集是不同的(其中GetACP()
和GetConsoleCP()
从WinAPI返回了不同的东西)。例如,在德国(可能还有其他西欧国家),Windows使用代码页1252作为整个字符集,但它使用代码页850作为控制台cmd.exe
。不确定原因,但就是这样。Golang错误地使用了GetACP()
对UTF-8的输入进行解码,而UTF-8本应使用GetConsoleCP()
返回的代码页。我们在我创建的代码中发现了问题,希望下一版本的Golang能够合并修复程序
我们还发现,在Golang将字符解码为分解的UTF-8字符的窗口上存在一个问题(即,Golang将a
ä
读取到字符a
,然后再进行组合分解
)这可能会导致其他问题,例如打印这些分解的字符会将它们打印为单独的字符,而不是一个组合字符。因此,对于某些系统来说,Golang中存在一个bug,具体来说,对于Windows系统来说,使用的总字符集和控制台字符集是不同的(其中GetACP()
和GetConsoleCP()
从WinAPI返回了不同的内容)。例如,在德国(可能还有其他西欧国家),Windows使用代码页1252作为整个字符集,但它使用代码页850作为控制台cmd.exe
。不确定原因,但就是这样。Golang错误地使用了GetACP()
对UTF-8的输入进行解码,而UTF-8本应使用GetConsoleCP()
返回的代码页。我们在我创建的代码中发现了问题,希望下一版本的Golang能够合并修复程序
我们还发现,在Golang将字符解码为分解的UTF-8字符的窗口上存在一个问题(即,Golang将a
ä
读取到字符a
,然后再进行组合分解
)这可能会导致其他问题,例如打印这些分解的字符会将它们分开打印,而不是打印一个组合字符。您没有回答自己的问题吗?Go默认采用UTF8,并且您正在输入CP850Go,如果从终端(cmd.exe)运行,则其源代码中的字符串将采用UTF-8它不应该正确读取stdin并从终端代码页转换为UTF-8吗?即使Go希望从控制台获得UTF-8,这也不能解释为什么我得到一个完全不相关的UTF-8字符,而不仅仅是错误符文。即使我直接从stdin读取字节,我也会收到这三个字节,而控制台肯定不会将其作为我的C-fu发送nction正确接收ä
的CP850值。因为Golang将输入解释为代码页1252,而不是850,即使控制台使用850。您没有回答自己的问题吗?Go默认采用UTF8,您输入的CP850Go在其源代码中对字符串采用UTF-8,但如果从终端(cmd.exe)运行它不应该正确读取stdin并从终端代码页转换为UTF-8吗?即使Go希望从控制台获得UTF-8,这也不能解释为什么我得到一个完全不相关的UTF-8字符,而不仅仅是错误符文。即使我直接从stdin读取字节,我也会收到这三个字节,而控制台肯定不会将其作为我的C-fu发送nction正确接收ä
的CP850值,因为Golang将输入解释为代码页1252而不是850,即使控制台使用850。
C:\dev\golang>go run test.go
ä
0xC3 0xA4 0xA