12

我有一个exe打印utf-8编码字符串的 in go,其中包含特殊字符。
由于该 exe 是从控制台窗口使用的,因此它的输出被破坏,因为 Windows 使用ibm850编码(aka code page 850)。

您将如何确保exe为控制台窗口打印正确编码的字符串,例如打印:

éèïöîôùòèìë

而不是(没有任何翻译到正确的字符集

├®├¿├»├Â├«├┤├╣├▓├¿├¼├½
4

4 回答 4

3
// Alert: This is Windows-specific, uses undocumented methods, does not
// handle stdout redirection, does not check for errors, etc.
// Use at your own risk.
// Tested with Go 1.0.2-windows-amd64.

package main

import "unicode/utf16"
import "syscall"
import "unsafe"

var modkernel32 = syscall.NewLazyDLL("kernel32.dll")
var procWriteConsoleW = modkernel32.NewProc("WriteConsoleW")

func consolePrintString(strUtf8 string) {
    var strUtf16 []uint16
    var charsWritten *uint32

    strUtf16 = utf16.Encode([]rune(strUtf8))
    if len(strUtf16) < 1 {
        return
    }

    syscall.Syscall6(procWriteConsoleW.Addr(), 5,
        uintptr(syscall.Stdout),
        uintptr(unsafe.Pointer(&strUtf16[0])),
        uintptr(len(strUtf16)),
        uintptr(unsafe.Pointer(charsWritten)),
        uintptr(0),
        0)
}

func main() {
    consolePrintString("Hello ☺\n")
    consolePrintString("éèïöîôùòèìë\n")
}
于 2012-08-21T16:48:23.520 回答
2

在线书籍“使用 Go 进行网络编程”(CC BY-NC-SA 3.0)有一章是关于字符集(管理字符集和编码)的,其中Jan Newmarch详细介绍了一个字符集到另一个字符集的转换。但这似乎很麻烦。

这是一个解决方案(我可能错过了一个更简单的解决方案),使用go-charset(来自Roger Peppe)。
我将一个utf-8字符串转换为一个ibm850编码的字符串,允许我在 DOS 窗口中打印:

éèïöîôùòèìë

翻译功能详解如下:

package main

import (
    "bytes"
    "code.google.com/p/go-charset/charset"
    _ "code.google.com/p/go-charset/data"
    "fmt"
    "io"
    "log"
    "strings"
)

func translate(tr charset.Translator, in string) (string, error) {
    var buf bytes.Buffer
    r := charset.NewTranslatingReader(strings.NewReader(in), tr)
    _, err := io.Copy(&buf, r)
    if err != nil {
        return "", err
    }
    return string(buf.Bytes()), nil
}

func Utf2dos(in string) string {
    dosCharset := "ibm850"
    cs := charset.Info(dosCharset)
    if cs == nil {
        log.Fatal("no info found for %q", dosCharset)
    }
    fromtr, err := charset.TranslatorTo(dosCharset)
    if err != nil {
        log.Fatal("error making translator from %q: %v", dosCharset, err)
    }
    out, err := translate(fromtr, in)
    if err != nil {
        log.Fatal("error translating from %q: %v", dosCharset, err)
    }
    return out
}

func main() {
    test := "éèïöîôùòèìë"
    fmt.Println("utf-8:\n", test)
    fmt.Println("ibm850:\n", Utf2dos(test))
}
于 2012-08-21T10:41:42.353 回答
2

自 2016 年以来,您现在(2017 年)可以考虑golang.org/x/text,它带有一个编码charmap,包括 ISO-8859 系列以及 Windows 1252 字符集。

见“ Go Quick-Converting Character Encodings In Golang

r := charmap.ISO8859_1.NewDecoder().Reader(f)
io.Copy(out, r)

my_isotext.txt这是打开 ISO-8859-1 源文本 ( )、创建目标文件 ( my_utf.txt) 并将第一个文件复制到第二个文件的示例的摘录。
但是为了从 ISO-8859-1 解码到 UTF-8,我们用解码器包装了原始文件读取器 ( f)。

我刚刚测试过(用于说明的伪代码):

package main

import (
    "fmt"

    "golang.org/x/text/encoding"
    "golang.org/x/text/encoding/charmap"
)

func main() {
    t := "string composed of character in cp 850"
    d := charmap.CodePage850.NewDecoder()
    st, err := d.String(t)
    if err != nil {
        panic(err)
    }
    fmt.Println(st)
}

结果是在 Windows CMD 中可读的字符串。在这个2018 年 11 月的 reddit 线程
中查看更多信息。

于 2017-07-08T20:29:14.343 回答
0

这是 Go 仍然无法开箱即用的事情 - 请参阅http://code.google.com/p/go/issues/detail?id=3376#c6

亚历克斯

于 2012-08-22T00:30:10.327 回答