在包含 ANSI 转义代码的字符串的第 80 个字符后自动添加换行符。

huangapple go评论73阅读模式
英文:

Automatically add New Line(s) after 80th character in a string containing ANSI Escape Codes

问题

我想要一个Go程序,能够显示一个使用CP437编码的ANSI艺术文件,宽度为80列,其中包含ANSI转义码(颜色、光标定位等)和扩展的ANSI(CP437)框图代码。

当在Linux终端中查看ANSI文件(请参见下面的Playground链接),并且使用80列的CP437兼容终端时,文件会正确显示,例如换行符会被隐式读取;然而,当使用更宽的终端查看时(这是目标),新的行不会被隐式处理/添加,文件可能会显示不正确,没有必要的换行符。

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

我已经尝试过像ansiwrap和reflow这样的Go库。ansiwrap只是用于文本换行,但是Reflow最接近目标,但换行符不太正确。

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

在CP437终端(132x37)中的渲染效果:

在包含 ANSI 转义代码的字符串的第 80 个字符后自动添加换行符。

应该的外观(来自艺术程序):

在包含 ANSI 转义代码的字符串的第 80 个字符后自动添加换行符。

英文:

I want a Go program to display a CP437-encoded 'ANSI art file', 80 columns wide, that contains ANSI escape codes -- color, cursor placement, etc. and extended ANSI (CP437) box drawing codes.

When viewing the ANSI file in a linux terminal (see Playground link below) with a 80 col CP437-capable terminal, the file displays properly, e.g. line breaks are implicitly read; however, when viewing with a wider terminal (which is the goal), new lines are not implicitly processed/added and the file may display improperly, without required line breaks.

How do I iterate through the .ans file and manually add new lines after the 80th character, counting only the actual characters displayed (not the escape codes)?

I've tried go libraries like ansiwrap and reflow. Ansiwrap is really just for text wrapping, but Reflow gets the closest to the goal, but the line breaks are not quite right.

Playground link of my test code with Reflow.

How it renders (in a CP437 terminal, 132x37):

在包含 ANSI 转义代码的字符串的第 80 个字符后自动添加换行符。

How it should look (from art program):

在包含 ANSI 转义代码的字符串的第 80 个字符后自动添加换行符。

答案1

得分: 1

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

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
英文:

To solve this, first I pulled visualLength function from the
golang.org/x/term package 1, then I wrote a bufio.SplitFunc 2 for this
use case.

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
}

Result:

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

huangapple
  • 本文由 发表于 2021年7月11日 06:01:58
  • 转载请务必保留本文链接:https://go.coder-hub.com/68331856.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定