首页 > 解决方案 > 在包含 ANSI 转义码的字符串中的第 80 个字符后自动添加新行

问题描述

我想要一个 Go 程序来显示一个 80 列宽的 CP437 编码的“ ANSI 艺术文件”,其中包含ANSI 转义码——颜色、光标位置等以及扩展的 ANSI(CP437)方框图代码。

在具有 80 col CP437-capable 终端的 linux 终端(参见下面的 Playground 链接)中查看 ANSI 文件时,文件显示正确,例如,隐式读取换行符;但是,当使用更宽的终端(这是目标)查看时,不会隐式处理/添加新行,并且文件可能会显示不正确,而无需换行。

如何遍历 .ans 文件并在第 80 个字符后手动添加新行,只计算显示的实际字符(而不是转义码)?

我试过像ansiwrapreflow这样的库。Ansiwrap 真的只是为了文本换行,但 Reflow 最接近目标,但换行符不太对。

我的测试代码与 Reflow 的Playground 链接

它如何呈现(在 CP437 终端中,132x37):

在终端应用程序中查看 132x37

应该看起来如何(来自艺术程序):

参考图像

标签: goterminalextended-ascii

解决方案


为了解决这个问题,我首先visualLength从包 [1] 中提取函数 golang.org/x/term,然后我为这个用例编写了一个bufio.SplitFunc[2]。

package main

func ansi(data []byte, eof bool) (int, []byte, error) {
   var s []rune
   for i, r := range string(data) {
      if s = append(s, r); visualLength(s) == 80 {
         width := len(string(r))
         return i+width, data[:i+width], nil
      }
   }
   return 0, nil, nil
}

结果:

package main

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

func main() {
   f, err := os.Open("LDA-PHASE90.ANS")
   if err != nil {
      panic(err)
   }
   defer f.Close()
   s := bufio.NewScanner(charmap.CodePage437.NewDecoder().Reader(f))
   s.Split(ansi)
   for s.Scan() {
      println(s.Text())
   }
}
  1. https://github.com/golang/term/blob/6886f2df/terminal.go#L431-L450
  2. https://golang.org/pkg/bufio#SplitFunc

推荐阅读