Home > other >  Backspace character does not work in the Go playground
Backspace character does not work in the Go playground

Time:04-18

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.)

CodePudding user response:

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.

CodePudding user response:

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

  • Related