In my compilers class, I decided to write my compiler in Python since I enjoy programming in Python, though I encountering an interesting issue with how characters are printed. The lexer I'm writing requires that strings containing the formfeed and backspace characters be printed to stdout in a very particular way: enclosed in double quotes, and printed as \f and \b, respectively. The closest I've gotten:
print("{0!r}".format("\b\f"))
which yields
'\x08\x0c'
Note the single quotes, and utf8 coding. The same command with two other characters I'm concerned with almost works:
print("{0!r}".format("\n\t"))
gives:
'\n\t'
To be clear, the result (including quotes) that I need to conform to the spec is
"\b\f"
Simple approaches like finding \b and \f and replacing them with "\b" and "\f" don't seem to work...the "\" is just the way Python prints a backslash, so I can never seem to get just "\b\f" as one might expect.
Playing with various string encodings doesn't seem to help. I've concluded that I need to write a custom string.Formatter, but I was wondering if there is another approach that I'd missed.
EDIT: Thanks for all the answers. I don't think I did that good of a job asking the question though. The underlying issue is that I'm formatting the strings as raw because I want literal newlines to appear as "\n" and literal tabs to appear as "\t". However, when I move to print the string using raw formatting, I lose the ability to print out "\b" and "\f" as all the answers below suggest.
I'll confirm this tonight, but based on these answers, I think the approach I should be using is to format the output normally, and trap all the literal "\n", "\t", "\b", and "\f" characters with escape sequences that will print them as needed. I'm still hoping to avoid using string.Formatter.
EDIT2: The final approach I'm going to use is to use non-raw string formatting. The non-abstracted version looks something like:
print('"{0!s}"'.format(a.replace("\b", "\\b").replace("\t", "\\t").replace("\f", "\\f").replace("\n","\\n")))
解决方案print("{0!r}".format("\b\f".replace("\b", "\\b").replace("\f", "\\f")))
Or, more cleanly:
def escape_bs_and_ff(s):
return s.replace("\b", "\\b").replace("\f", "\\f")
print("{0!r}".format(escape_bs_and_ff("\b\f"))