Skip to content
Backslash Escapes
step 1/5

Reading — step 1 of 5

Learn

~3 min readProduction Concerns

Backslash Escapes

Escaping HTML handles characters on the way out: a < in the source becomes &lt; in the output. Backslash escapes are the mirror problem, on the way in. An author who wants a literal asterisk in the rendered text needs a way to tell the parser "this one is not markup", and a backslash is the only tool Markdown gives them.

What can be escaped?

Exactly the 32 ASCII punctuation characters, and nothing else.

\*not emphasized*  ->  *not emphasized*
\# not a heading   ->  # not a heading
1\. not a list     ->  1. not a list
\a and \3          ->  \a and \3

A backslash before a letter, a digit, a space, or a non-ASCII character is just a backslash. Markdown is a plain-text format first, and Windows paths and LaTeX fragments have to survive it intact.

Why can't you just strip the backslashes?

Because whichever order you pick, one pass ruins the other. Strip first and the emphasis pass sees a bare asterisk and treats it as markup. Strip last and the emphasis pass has already consumed the asterisk you were protecting.

The way out is to take the character out of the string entirely: replace it with a placeholder no other rule can match, run every other pass, and put the real character back at the very end.

python

Line one is the bug in miniature: the author asked for a literal asterisk and got emphasis anyway. Line two is the same document with the escape honoured, and the real emphasis later in the line still works.

Which contexts ignore escapes?

Inside verbatim spans a backslash is just a byte, so the rule is off:

Context\[ renders as
paragraph text[
link destination or title[
fenced code info string[
code span or code block\[
autolink or raw HTML\[

That last group is why a production pipeline stashes code spans before it stashes escapes. Both stashes use the same trick; the order between them is what decides whether `\[` keeps its backslash.

Two rules that catch people

An escaped backslash does not escape the next character. \\*x* is one literal backslash followed by real emphasis, because the first backslash consumed the second. Walk the string left to right taking two characters at a time and you get that for free; reach for str.replace and you will not.

And a backslash at the very end of a line is not an escape at all — it is a hard line break. That rule belongs to paragraph assembly, not to this pass, so an escape pass that works one line at a time should leave a trailing backslash alone.

Your exercise

Stash escapes, escape HTML, apply emphasis, restore.

The mistake the grader catches is restoring too early. A visible test feeds \*not emphasized*; if you put the asterisk back before the emphasis pass runs, the pass sees two asterisks in *not emphasized* and wraps the line in <em>. Restore last, after every other rule has had its turn.

The second one is the placeholder itself. Your stash runs before escape_html, so the placeholder has to be something escaping cannot touch — digits between two NUL bytes work, a string like [[0]] does not, because a later rule can match brackets. And a restored character goes back through escape_html too: a hidden test feeds both \< and a bare < on one line and expects &lt; for each.

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…

Backslash Escapes — Build a Markdown to HTML Converter