如何使用go在Windows控制台中正确输出字符串?

我有一个 exe </ code>可以打印 utf-8 编码的字符串,其中带有特殊字符。

由于exe是从控制台窗口使用的,因此其输出 由于Windows使用 ibm850 </ code>编码(即 代码页850 </ 代码> )。</ p>

如何确保go exe </ code>为控制台窗口正确打印编码后的字符串,例如打印: p>

 éèïöîôùùèèë
</ code> </ pre>

(而不是字符集)</ p>

 ├®├¿├»├├  «├┤├╣├▓├¿├¼├½
</ code> </ pre>
</ div>

展开原文

原文

I have a exe in go which prints utf-8 encoded strings, with special characters in it.
Since that exe is made to be used from a console window, its output is mangled because Windows uses ibm850 encoding (aka code page 850).

How would you make sure the go exe print correctly encoded strings for a console windows, ie print for instance:

éèïöîôùòèìë

instead of (without any translation to the right charset)

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

4个回答



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

请参阅“ 快速进行-在Golang中转换字符编码 “ </ p>

  r:= charmap.ISO8859_1.NewDecoder()。Reader(f)
io.Copy(out,r)
</ code> </ pre> \ n

这是打开ISO-8859-1源文本( my_isotext.txt </ code>),创建目标文件( my_utf.txt </ code>)的示例的摘录 ),然后将第一个复制到第二个。

但是,要从ISO-8859-1解码为UTF-8,我们需要使用解码器包装原始文件阅读器( f </ code>)。</ br p>
\ n

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

  package main 

import(
“ fmt “

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

func main(){
t:=”字符串由 cp 850中的字符“
d:= charmap.CodePage850.NewDecoder()
st,err:= d.String(t)
如果err!= nil {
panic(err)
}
fmt。 Println(st)
}
</ code> </ pre>

结果是Windows CMD中可读的字符串。

请参见此十一月。 2018 reddit线程。</ p>
</ div>

展开原文

原文

Since 2016, You can now (2017) consider the golang.org/x/text, which comes with a encoding charmap including the ISO-8859 family as well as the Windows 1252 character set.

See "Go Quickly - Converting Character Encodings In Golang"

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

That is an extract of an example opening a ISO-8859-1 source text (my_isotext.txt), creating a destination file (my_utf.txt), and copying the first to the second.
But to decode from ISO-8859-1 to UTF-8, we wrap the original file reader (f) with a decoder.

I just tested (pseudo-code for illustration):

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)
}

The result is a string readable in a Windows CMD.
See more in this Nov. 2018 reddit thread.

The online book "Network programming with Go" (CC BY-NC-SA 3.0) has a chapter on Charsets (Managing character sets and encodings), in which Jan Newmarch details the conversion of one charset to another. But it seems cumbersome.

Here is a solution (I might have missed a much simpler one), using the library go-charset (from Roger Peppe).
I translate an utf-8 string to an ibm850 encoded one, allowing me to print in a DOS windows:

éèïöîôùòèìë

The translation function is detailed below:

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:
", test)
    fmt.Println("ibm850:
", Utf2dos(test))
}
dongtou5557
dongtou5557 还有我下面的其他答案? (stackoverflow.com/a/44990465/6309)
接近 2 年之前 回复
dragon87836215
dragon87836215 不再编译
接近 2 年之前 回复
// 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 ☺
")
    consolePrintString("éèïöîôùòèìë
")
}
dongtu0363
dongtu0363 有趣的(+1),但我可能暂时保留我的方法,这似乎比使用不安全的方法更可靠。
大约 8 年之前 回复



这是Go仍然无法立即使用的功能-请参见 http://code.google.com/p/go/issues/detail?id=3376#c6 </ p>

Alex </ p>
</ div>

展开原文

原文

It is something that Go still can't do out of the box - see http://code.google.com/p/go/issues/detail?id=3376#c6.

Alex

dongpangzan6425
dongpangzan6425 好点子。 在我的特定情况下,转换库中存在的子集就足够了,但是我同意您的意见,如上面的jason_s的代码所示
大约 8 年之前 回复
dongwei6457
dongwei6457 如果您的控制台使用ibm850代码页,那么您的解决方案很好。 但是,据我所知,那里只能有许多不同的字符。 它不会包含大多数Unicode字符。 为了具有最大的包容性,您应该使用utf16代码页和WriteConsoleW输出文本。
大约 8 年之前 回复
dtn913117
dtn913117 我的意思是,3346更加清楚地说明了手头的问题,而它的父级(3376)更为广泛。 那么,您是说我是在使用外部库来实现正确的输出?
大约 8 年之前 回复
douang4294
douang4294 当然。 但是它被标记为3376的重复项。无论哪种方式,它仍然需要完成。
大约 8 年之前 回复
du155305
du155305 我认为code.google.com/p/go/issues/detail?id=3346与我的问题很接近,不是吗?
大约 8 年之前 回复
Csdn user default icon
上传中...
上传图片
插入图片
抄袭、复制答案,以达到刷声望分或其他目的的行为,在CSDN问答是严格禁止的,一经发现立刻封号。是时候展现真正的技术了!
立即提问
相关内容推荐