Golang在Windows系统中彩色文本显示异常问题

Golang在Windows系统中彩色文本显示异常问题 我有这段代码,但它只在Linux上有效。我需要怎么做才能让它能在Windows、Linux、Mac等系统上运行?

package main

import "fmt"

var (
  Info = Teal
  Warn = Yellow
  Fata = Red
)

var (
  Black   = Color("\033[1;30m%s\033[0m")
  Red     = Color("\033[1;31m%s\033[0m")
  Green   = Color("\033[1;32m%s\033[0m")
  Yellow  = Color("\033[1;33m%s\033[0m")
  Purple  = Color("\033[1;34m%s\033[0m")
  Magenta = Color("\033[1;35m%s\033[0m")
  Teal    = Color("\033[1;36m%s\033[0m")
  White   = Color("\033[1;37m%s\033[0m")
)

 func Color(colorString string) func(...interface{}) string {
  sprint := func(args ...interface{}) string {
    return fmt.Sprintf(colorString,
    fmt.Sprint(args...))
   }
  return sprint
}

func main() {
  fmt.Println(Info("hello, world!"))
}

更多关于Golang在Windows系统中彩色文本显示异常问题的实战教程也可以访问 https://www.itying.com/category-94-b0.html

7 回复

我曾希望有一个适用于所有操作系统的简便方法。

更多关于Golang在Windows系统中彩色文本显示异常问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


你有任何示例吗?或者我可以在哪里找到相关信息?

它不会。这是Linux(可能还有Mac,我不确定)的一个特性,但不是Windows的。Windows确实有实现颜色的方法,但它的系统比Linux上的更简单。

可能存在一些库,它们对系统进行了封装,让你可以直接使用它们的API。

不过,到目前为止,我还没有在Go中使用过这样的库。

上次使用是在Ruby中,效果并不好。它的API不像Windows原生的那样笨拙,但也不像Linux的那么直接。而且它在每个字符后都会刷新流……体验并不好……

通常,最简单的做法是在Windows上干脆不使用颜色。

Windows 为什么比 Linux 复杂得多,因为 Windows 需要一些函数调用来处理字符流。包括每隔几个字节就显式刷新,以确保新颜色能从正确的字符开始应用。

不过据我所知,现代的 Windows 终端(在 Win10 的某个版本中引入)能够理解用于着色的 ANSI 代码。

也许这仅限于 Powershell?不太确定……

有一个库演示了如何在 Windows 上实现这一点。其核心在于通过系统调用来告知操作系统如何表现。

GitHub

fatih/color

Avatar

Go (golang) 的颜色包。通过在 GitHub 上创建账户来为 fatih/color 的开发做出贡献。

真正的魔法在于:

mattn/go-colorable/blob/master/colorable_windows.go

// +build windows
// +build !appengine

package colorable

import (
	"bytes"
	"io"
	"math"
	"os"
	"strconv"
	"strings"
	"syscall"
	"unsafe"

	"github.com/mattn/go-isatty"
)

const (
	foregroundBlue      = 0x1

此文件已被截断。显示原文

在Windows系统中,ANSI转义序列默认不被支持。需要使用第三方库或系统调用来启用控制台虚拟终端序列。以下是使用github.com/inancgumus/screen库的解决方案:

package main

import (
    "fmt"
    "runtime"
    "syscall"
    "unsafe"
)

var (
    kernel32 = syscall.NewLazyDLL("kernel32.dll")
    procSetConsoleMode = kernel32.NewProc("SetConsoleMode")
)

func enableWindowsANSI() bool {
    if runtime.GOOS != "windows" {
        return true
    }
    
    handle := syscall.Handle(os.Stdout.Fd())
    var mode uint32
    err := syscall.GetConsoleMode(handle, &mode)
    if err != nil {
        return false
    }
    
    mode |= 0x0004 // ENABLE_VIRTUAL_TERMINAL_PROCESSING
    ret, _, err := procSetConsoleMode.Call(uintptr(handle), uintptr(mode))
    return ret != 0
}

var (
    Info = Teal
    Warn = Yellow
    Fata = Red
)

var (
    Black   = Color("\033[1;30m%s\033[0m")
    Red     = Color("\033[1;31m%s\033[0m")
    Green   = Color("\033[1;32m%s\033[0m")
    Yellow  = Color("\033[1;33m%s\033[0m")
    Purple  = Color("\033[1;34m%s\033[0m")
    Magenta = Color("\033[1;35m%s\033[0m")
    Teal    = Color("\033[1;36m%s\033[0m")
    White   = Color("\033[1;37m%s\033[0m")
)

func Color(colorString string) func(...interface{}) string {
    return func(args ...interface{}) string {
        return fmt.Sprintf(colorString, fmt.Sprint(args...))
    }
}

func main() {
    if !enableWindowsANSI() {
        fmt.Println("警告: 无法启用Windows ANSI支持,颜色可能无法显示")
    }
    
    fmt.Println(Info("hello, world!"))
    fmt.Println(Warn("这是一个警告"))
    fmt.Println(Fata("这是一个错误"))
}

或者使用跨平台的github.com/fatih/color库:

package main

import (
    "github.com/fatih/color"
)

var (
    Info = color.New(color.FgCyan).SprintFunc()
    Warn = color.New(color.FgYellow).SprintFunc()
    Fata = color.New(color.FgRed).SprintFunc()
)

func main() {
    fmt.Println(Info("hello, world!"))
    fmt.Println(Warn("这是一个警告"))
    fmt.Println(Fata("这是一个错误"))
}

对于更简单的解决方案,可以使用条件编译:

// +build !windows

package main

import "fmt"

var (
    Black   = Color("\033[1;30m%s\033[0m")
    Red     = Color("\033[1;31m%s\033[0m")
    // ... 其他颜色定义
)

// +build windows

package main

import "fmt"

var (
    Black   = fmt.Sprintf
    Red     = fmt.Sprintf
    // ... Windows下禁用颜色
)

使用golang.org/x/term检测终端能力:

package main

import (
    "fmt"
    "golang.org/x/term"
    "os"
)

func isColorSupported() bool {
    return term.IsTerminal(int(os.Stdout.Fd()))
}

func Color(colorString string) func(...interface{}) string {
    return func(args ...interface{}) string {
        if !isColorSupported() {
            return fmt.Sprint(args...)
        }
        return fmt.Sprintf(colorString, fmt.Sprint(args...))
    }
}
回到顶部