猿问

有没有更好的方法来实现模仿有限字符显示的水平滚动文本效果?

我试图在命令行上模仿 16 个字符的显示,它在一个长字符串上循环,无限类似于股票交易股票。


现在,我首先打印 ASCII 字符串的前 16 字节切片,并一次移动 1 个字节:


package main


import (

    "fmt"

    "time"

)


const (

    chars = 16

    text  = "There are many variations of passages of Lorem Ipsum available!!!"

)


func main() {

    fmt.Print("\033[2J") // clear screen

    buf := []byte(text)


    i := chars

    for {

        fmt.Print("\033[H") // move cursor back to first position

        fmt.Printf(string(buf[i-chars : i]))

        i++


        if i == len(buf)+1 {

            i = chars

        }


        time.Sleep(time.Second / 4)


        // visualization of what's happening:

        // fmt.Printf("\t\t Character:%d of Length:%d | Slice: %d:%d \n", i, len(buf), i-chars, i)

    }

}


当我到达文本末尾时,我重置循环内的计数器并从第一个切片开始再次打印。我不想这样做,而是想获得“翻转”效果,其中切片的头部无缝连接到切片的尾部。


问题是,我不能使用空缓冲区并将头部附加到循环内的尾部,因为它会无限增长。


因此,我没有这样做,而是决定在循环之前将字符串的前 16 个字节附加到其尾部,并立即缩小切片 -16 个字节。但由于 -16 字节仍然存在于支持数组中,我可以从循环中扩展/收缩:


func main() {

    fmt.Print("\033[2J") // clear screen

    buf := []byte(text)

    buf = append(buf, buf[:chars]...)

    buf = buf[:len(buf)-chars]


    var expanded bool

    i := chars

    for {

        fmt.Print("\033[H") // move cursor back to first position

        fmt.Printf(string(buf[i-chars : i]))

        i++


        if i+1 == len(buf)-chars && !expanded {

            buf = buf[:len(buf)+chars]

            expanded = true

        }


        if i+1 == len(buf) {

            i = chars

            buf = buf[:len(buf)-chars]

            expanded = false

        }


        time.Sleep(time.Second / 2)


        // visualization of what's happening:

        //fmt.Printf("\t\t Character:%d of Length:%d | Slice: %d:%d | Cap: %d\n", i, len(buf), i-chars, i, cap(buf))

    }

}

这让我到达了我想要的地方,但我对 Go 相当陌生,所以我想知道是否有更好的方法来达到相同的结果?


婷婷同学_
浏览 108回答 1
1回答

慕码人8056858

首先我不会改变缓冲区。0将前 16 个字符附加到其末尾以轻松获得“滚动”效果是一个好主意,但是当您到达末尾时将位置重置到更容易且更便宜。接下来,您不需要对字节切片进行操作。只需在string. 字符串可以像切片一样进行索引和切片,并且切片 astring甚至不会进行复制(不必),它会返回一个新字符串(标头),该字符串共享字符串数据的后备数组。不要忘记索引和切片string使用字节索引(不是rune索引),这对于 ASCII 文本来说很好(它们的字符在 UTF-8 中一对一映射到字节),但不适用于多字节特殊字符。你的示例文本很好。也不要用于fmt.Printf()打印需要格式的文本string(将其第一个参数视为格式字符串)。相反,只需使用fmt.Print().总而言之,您的解决方案可以简化为这样,这在性能方面要好得多,而且更干净、更简单:func main() {    fmt.Print("\033[2J") // clear screen    s := text + text[:chars]    for i := 0; ; i = (i + 1) % len(text) {        fmt.Print("\033[H") // move cursor back to first position        fmt.Print(s[i : i+chars])        time.Sleep(time.Second / 2)    }}另请注意,当位置达到 时len(text),我们将其重置为0,因此之前的文本从最后一个字符开始text并chars-1从头开始使用。因此,附加chars-1而不是chars:s := text + text[:chars-1]
随时随地看视频慕课网APP

相关分类

Go
我要回答