退格字符在Go Playground中无法正常工作。

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

Backspace character does not work in the Go playground

问题

我是你的中文翻译助手,以下是翻译好的内容:

我刚开始学习Go语言,刚刚学会了fmt.Println()的各种用法。我在官方的代码运行环境中尝试了以下代码,但得到了一个非常出乎意料的输出结果。请解释一下我对代码的理解哪里出错了。

输入:fmt.Println("hi\b", "there!")
输出:hi� there!
预期:h there!

输入:fmt.Println("hi", '\b', "there!")
输出:hi 8 there!
预期:hithere!... 假设符文不会附加空格

输入:fmt.Println("hi", "\bthere!")
输出:hi �there!
预期:hithere!

(注意:上面的占位符字符已被替换为U+FFFD,因为原始字符在不同环境中的呈现方式不一致。)

英文:

I am new to Go. Just learnt the various uses of fmt.Println(). I tried the following stuff in the official playground but got a pretty unexpected output. Please explain where I have gone wrong in my understanding.

input: fmt.Println("hi\b", "there!")
output: hi� there!
expected: h there!

input: fmt.Println("hi", '\b', "there!")
output: hi 8 there!
expected: hithere!... assuming runes are not appended with spaces

input: fmt.Println("hi", "\bthere!")
output: hi �there!
expected: hithere!


(Note: above, the placeholder character has been substituted by U+FFFD, as the original character does not render consistently between environments.)

答案1

得分: 4

您的程序输出的正是您告诉它要输出的内容。问题主要出在输出查看器上。

控制字符和序列只有在发送到兼容的虚拟控制台(或物理终端、打印机或电传打字机,但这些设备如今相当罕见)时才会产生预期的效果。Go Playground 的做法是将程序的输出原样捕获,并将其未经修改地发送到浏览器进行显示。浏览器不会解释终端控制代码(除了换行符,即使是换行符有时也只是部分解释);相反,它期望通过 HTML 标记传递格式化信息。由于退格字符没有分配的字形,浏览器通常会显示一个占位符字形,或者有时根本不显示任何内容。

如果在本地计算机上运行 Go 程序时,将其输出重定向到文本文件,然后在文本编辑器中打开该文件,您将获得类似的效果:编辑器不会解释文本文件中包含的任何转义序列;有时,它甚至会主动阻止终端显示编辑器的控制字符(如果它恰好是基于控制台的编辑器),而是用符号化的、常规的字符表示(如 ^H)。

在中间的示例中,'\b' 字面量被评估为具有字符的 Unicode 代码点数值的整数(Go 中称为“rune”)。这在规范中有解释

> 一个 rune 字面量表示一个 rune 常量,即标识 Unicode 代码点的整数值。一个 rune 字面量表示为一个或多个字符,用单引号括起来,如 'x''\n'。在引号内,除了换行符和未转义的单引号之外,任何字符都可以出现。单引号字符表示字符本身的 Unicode 值,而以反斜杠开头的多字符序列以各种格式编码值。

由于 '\b' 表示的是 U+0008,传递给 fmt.Println 的是整数值 8。该函数然后将整数作为十进制表示打印出来,而不是将其解释为字符代码。

英文:

Your program outputs exactly what you told it to. The problem is mostly with your output viewer.

Control characters and sequences only have their expected effect when sent to a compatible virtual console (or a physical terminal, or a printer or teletypewriter; but the latter are pretty rare these days). What the Go playground does is capture the output of your program as-is and send it unmodified to the browser to display. The browser does not interpret terminal control codes (other than the newline character, and even that only sometimes); instead, it expects formatting to be conveyed via HTML markup. Since the backspace character does not have an assigned glyph, browsers will usually display a placeholder glyph instead, or sometimes nothing at all.

You would get a similar effect if, when running your Go program on your local machine, you redirected its output into a text file and then opened the file in a text editor: the editor will not interpret any escape sequence contained in the text file; sometimes it will even actively prevent control characters from being interpreted by the terminal displaying the editor (if it happens to be console-based editor), by substituting a symbolic, conventional representation of the character like ^H.

In the middle example, the '\b' literal evaluates to an integer with the value of the character’s Unicode code point number (what Go terms a ‘rune’). This is explained in the specification:

> A rune literal represents a rune constant, an integer value identifying a Unicode code point. A rune literal is expressed as one or more characters enclosed in single quotes, as in 'x' or '\n'. Within the quotes, any character may appear except newline and unescaped single quote. A single quoted character represents the Unicode value of the character itself, while multi-character sequences beginning with a backslash encode values in various formats.

Since '\b' represents U+0008, what is passed to fmt.Println is the integer value 8. The function then prints the integer as its decimal representation, instead of interpreting it as a character code.

答案2

得分: 1

首先要检查的是你的终端,'\b' 是终端相关的,检查一下运行你的程序的终端是否将其处理为“将光标向后移动一个字符”(大多数类Unix系统会这样做,我不清楚Windows),在我的终端(st)上,你给出的第一个和第三个示例的输出与你的期望完全一致。

这里你的假设与 fmt 包的行为不符:

对于每个类似 Printf 的函数,还有一个不带格式的 Print 函数,它等同于对每个操作数使用 %v。另一个变体 Println 在操作数之间插入空格并追加一个换行符。

Fmt 将 rune 的 %v 格式化为 %d,而不是 %c,所以 '\b' 被格式化为 "8"(ASCII 值为 56),而不是 '\b'(ASCII 值为 8)。此外,如果 rune 处于两个参数之间,它们之间会有一个空格。

对于这个输入,Println 的处理过程如下:

打印字符串 "hi"

打印空格

格式化数字 8,然后打印字符串 "8"

打印空格

打印字符串 "there!"

要调试类似渲染不可见字符的问题,我建议你使用 encoding/hex 包,例如:

package main

import (
	"encoding/hex"
	"fmt"
	"os"
)

func main() {
	d := hex.Dumper(os.Stdout)
	defer d.Close()

	fmt.Fprintln(d, "hi", '\b', "there!")
}

输出结果:00000000 68 69 20 38 20 74 68 65 72 65 21 0a |hi 8 there!.|
Playground: https://go.dev/play/p/F-I2mdh43K7

英文:

First thing to check out is your terminal, '\b' is terminal dependent, check if the terminal running your program handles that as "move cursor one character back" (most unixes-like will, i don't know about Windows), your first and third given example works exactly how your expectation is on my terminal (st).

> input: fmt.Println("hi", '\b', "there!")
>
> output: hi 8 there!
>
> expected: hithere!... assuming runes are not appended with spaces
>

Here your assumption is not what package fmt does:

> For each Printf-like function, there is also a Print function that takes no format and is equivalent to saying %v for every operand. Another variant Println inserts blanks between operands and appends a newline.

Fmt handles %v for rune as %d, not %c, so '\b' is formatted as "8" (ascii value 56), not the '\b' (ascii value 8). Also runes will have a space if they are between two arguments.

What Println does for this input is:

print string "hi"

print space

format number 8 then print string "8"

print space

print string "there!"

To debug problems like rendering invisible characters, I suggest you to use encoding/hex package, For example:

package main

import (
	"encoding/hex"
	"fmt"
	"os"
)

func main() {
	d := hex.Dumper(os.Stdout)
	defer d.Close()

	fmt.Fprintln(d, "hi", '\b', "there!")
}

Output: 00000000 68 69 20 38 20 74 68 65 72 65 21 0a |hi 8 there!.|
Playground: https://go.dev/play/p/F-I2mdh43K7

huangapple
  • 本文由 发表于 2022年4月16日 17:41:50
  • 转载请务必保留本文链接:https://go.coder-hub.com/71892768.html
匿名

发表评论

匿名网友

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

确定