Skip to content

Step 1 of 5 · Reading · ~3 min

Read

Inline Elements

Bold and Italic

*italic*   or  _italic_    ->  <em>italic</em>
**bold**   or  __bold__    ->  <strong>bold</strong>
**bold *and italic***      ->  <strong>bold <em>and italic</em></strong>

Emphasis is the part of Markdown that has the most edge cases per character of syntax, and the CommonMark spec spends more rules on it than on every block type combined. The reason is simple: an asterisk is also multiplication, a footnote marker, and a decorative bullet. The parser has to decide, per asterisk, whether it is markup or text.

When is an asterisk markup?

The spec's answer is flanking. An asterisk can open emphasis only if it is part of a left-flanking delimiter run: nothing whitespace-y directly after it, and if what follows is punctuation then something whitespace-y or punctuation must precede it. Closing is the mirror image.

Rendering diagram…

The first branch alone buys you most of the correctness a small parser needs:

python

Row two is the win: the lookarounds refuse a delimiter that touches whitespace, so ordinary arithmetic survives. Row three shows that mid-word emphasis with * is intentional and must keep working. Row four is where even the guarded pattern diverges from the spec — real CommonMark leaves a*"quoted"* alone, because an opener preceded by a letter and followed by punctuation is not left-flanking. A regex approximates the rule; only a delimiter-run scanner implements it.

Why do underscores behave differently?

Because snake_case_names are everywhere. _ may only open or close at a word boundary, so un_bel_ievable stays literal while un*bel*ievable emphasises. The asymmetry is deliberate, not an accident of history.

Which delimiter do you match first?

Longest run first, always. This is the same maximal-munch rule a lexer uses.

Order**bold** becomes
✓ try ** before *<strong>bold</strong>
✗ try * before ***<em>bold</em>*

One spec detail worth knowing: the reference renderer emits ***x*** as <em><strong>x</strong></em> — em on the outside, because the spec prefers the interpretation with the least nesting depth on the strong element. This course's tests use the opposite order, <strong><em>x</em></strong>, which is what most hand-written parsers produce. Match the tests here; remember the spec answer when you read someone else's output and it looks flipped.

Your exercise

Apply inline code, then ***x***, then **x**, then *x*, to each line.

The mistake the grader catches is an unguarded * pattern. One visible test is the line * spaced *, which must come back byte-for-byte unchanged. With \*(.+?)\* you emit <em> spaced </em> and fail. Add the (?=\S) and (?<=\S) guards.

The second one is subtler: **bold *and italic*** needs its own combined pattern. Running plain **...** over it consumes only two of the three closing asterisks and leaves a stray * in your output. Handle the strong-wrapping-em shape before the general ** rule, and stash each replacement you make so a later pass cannot re-enter the HTML you already produced.

Up nextThe Delimiter StackInline Elements

Discussion

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

Sign in to post a comment or reply.

Loading…