AI InterviewSearch…Search problems, topics, or pages…Ctrl KGet started
Skip to content

10 Strings, Unicode, regular expressions and parsing / Checkpoint

Checkpoint — Strings, Unicode, regular expressions and parsing

25 min · +25 XP · 3 exercises · 12 questions

Exercises0/3
Quiz · 70% to clear12 q

This checkpoint covers UTF-16 code units versus code points versus grapheme clusters, normalisation, case mapping and locale-aware comparison; the string toolbox, template literals, tagged templates and Intl formatting; regular-expression syntax, flags, groups, the five methods and lastIndex; lookarounds, Unicode property escapes, escaping input and catastrophic backtracking; and hand-written parsing with sticky tokenizers, recursive descent and CSV quoting.

How it works. Twelve questions and three programs; 70% on the questions and every program accepted clears the module.

Before you start, make sure you can answer:

  • Why "😀".length is 2; how to count code points and graphemes; what normalize("NFC") fixes; how toUpperCase can change length.
  • slice versus substring; what "".split(",") returns; what a tag function receives; why Intl formatters are created once.
  • Which flag makes test stateful; greedy versus lazy versus a negated class; how to get every match with groups.
  • What a lookahead is; why (\w+\s?)* is dangerous; how to escape user input for new RegExp.
  • Why the sticky flag suits tokenizers; where precedence lives in a recursive-descent parser; why split(",") cannot parse CSV.

The programs are a Unicode-aware word-statistics tool, a template renderer with filters and conditionals built on replace with a function, and an expression evaluator with variables, a sticky tokenizer and positioned errors.

Common questions

Can toUpperCase change the length of a string in JavaScript?

Yes. Case mapping is Unicode-aware, so "straße".toUpperCase() returns "STRASSE", one character longer. It is also locale-independent: Turkish text needs toLocaleUpperCase("tr") to turn i into a dotted capital İ.

Why are nested regex quantifiers dangerous?

A pattern that repeats a group whose parts can match the same text, such as a word followed by optional whitespace, repeated, gives the engine exponentially many ways to split a failing input, so matching time doubles with each extra character. That catastrophic backtracking lets one crafted request pin a CPU; rewrite the pattern so each repetition consumes something unambiguous.

Where does operator precedence live in a recursive-descent parser?

In the structure of the grammar, not in the order of if statements: the lowest-precedence rule sits at the top and calls the next rule for its operands, so expr handles + and - by calling term, which handles * and / by calling factor. Deeper rules bind tighter.

JavaScript Regex and Unicode Strings Quiz: Practice Test

Test your JavaScript strings with 12 questions and three programs on UTF-16 and Unicode, string methods, Intl, regex flags and groups, lookarounds and parsing.

  • Course: JavaScript study plan
  • Module: Strings, Unicode, regular expressions and parsing
  • Kind: Checkpoint — cleared at 70%
  • Reading time: 25 min
  • Runtime: Node 16

Checkpoint — Strings, Unicode, regular expressions and parsing is the checkpoint that closes the Strings, Unicode, regular expressions and parsing module: a graded quiz and whole-program exercises, passed at 70%.

Instructions

This checkpoint covers UTF-16 code units versus code points versus grapheme clusters, normalisation, case mapping and locale-aware comparison; the string toolbox, template literals, tagged templates and Intl formatting; regular-expression syntax, flags, groups, the five methods and lastIndex; lookarounds, Unicode property escapes, escaping input and catastrophic backtracking; and hand-written parsing with sticky tokenizers, recursive descent and CSV quoting.

How it works. Twelve questions and three programs; 70% on the questions and every program accepted clears the module.

Before you start, make sure you can answer:

  • Why "😀".length is 2; how to count code points and graphemes; what normalize("NFC") fixes; how toUpperCase can change length.
  • slice versus substring; what "".split(",") returns; what a tag function receives; why Intl formatters are created once.
  • Which flag makes test stateful; greedy versus lazy versus a negated class; how to get every match with groups.
  • What a lookahead is; why (\w+\s?)* is dangerous; how to escape user input for new RegExp.
  • Why the sticky flag suits tokenizers; where precedence lives in a recursive-descent parser; why split(",") cannot parse CSV.

The programs are a Unicode-aware word-statistics tool, a template renderer with filters and conditionals built on replace with a function, and an expression evaluator with variables, a sticky tokenizer and positioned errors.

Common questions

Can toUpperCase change the length of a string in JavaScript?

Yes. Case mapping is Unicode-aware, so "straße".toUpperCase() returns "STRASSE", one character longer. It is also locale-independent: Turkish text needs toLocaleUpperCase("tr") to turn i into a dotted capital İ.

Why are nested regex quantifiers dangerous?

A pattern that repeats a group whose parts can match the same text, such as a word followed by optional whitespace, repeated, gives the engine exponentially many ways to split a failing input, so matching time doubles with each extra character. That catastrophic backtracking lets one crafted request pin a CPU; rewrite the pattern so each repetition consumes something unambiguous.

Where does operator precedence live in a recursive-descent parser?

In the structure of the grammar, not in the order of if statements: the lowest-precedence rule sits at the top and calls the next rule for its operands, so expr handles + and - by calling term, which handles * and / by calling factor. Deeper rules bind tighter.

Exercises

Unicode-aware word statistics

Read the whole input. Extract words with Intl.Segmenter("en", { granularity: "word" }) keeping segments where isWordLike is true, normalise each to NFC and lower-case. Print words=<count> unique=<distinct>; top=<three most frequent as word=n, ties by localeCompare>; longest=<the distinct word with the most graphemes, ties by localeCompare> graphemes=<n> codeUnits=<length>; letters=<\p{L} count> digits=<\p{Nd} count> emoji=<\p{Extended_Pictographic} count> over the raw input; and sorted=<distinct words sorted with an Intl.Collator("en")>.

Example: The café was the CAFÉ we loved; the 日本語 menu had 3 items 😀 →

words=13 unique=10
top=the=3 café=2 3=1
longest=items graphemes=5 codeUnits=5
letters=42 digits=1 emoji=1
sorted=3 café had items loved menu the was we 日本語

The two spellings of café (precomposed and decomposed) became one word after normalisation.

A template renderer built on replace

Line 1 is a JSON context; the rest is a template. Implement render(tpl, ctx) with three passes of replace with functions: {{#each key}}…{{/each}} repeats the body for each array element with this and index added to the context (rendering the body recursively); {{#if key}}…{{/if}} keeps the body when the value is truthy; {{ path | filter | filter:arg }} looks up a dotted path and applies filters upper, lower, money (USD via Intl) and default:<text> (used when the value is undefined, null or empty); an unknown filter throws. Missing values render as empty. Print the result.

Example context {"name":"Ada","items":["pen","ink"],"total":12.5,"vip":true,"nick":""} and template

Hello {{ name | upper }}!
{{#if vip}}Welcome back.{{/if}}
{{#each items}}- {{ this | upper }} ({{ index }})
{{/each}}Total: {{ total | money }} for {{ nick | default:friend }}{{#if missing}} never{{/if}}

→

Hello ADA!
Welcome back.
- PEN (0)
- INK (1)
Total: $12.50 for friend

A calculator with variables and exponents

Extend the expression evaluator: tokens are numbers, identifiers and + - * / ^ ( ) =. A line is either name = expr (store the value in a Map, print name = value) or an expression (print its value). Grammar: term := unary (('*'|'/') unary)*, unary := '-' unary | power, power := primary ('^' unary)? — so ^ is right-associative, binds tighter than unary minus (-2 ^ 2 is −4) and allows a negative exponent. An unknown variable throws ReferenceError("unknown variable 'z' at <pos>"); other errors as in the previous exercise. Variables persist across lines.

Example:

x = 3 + 4
y = x * 2
y - x
2 ^ 3 ^ 2
-2 ^ 2
z + 1

→

x = 7
y = 14
7
512
-4
ReferenceError: unknown variable 'z' at 0

In this module: Strings, Unicode, regular expressions and parsing

← Parsing text by hand — tokenizers, recursive descent, CSV and error positions · Pure functions and immutability — why, and how far to take it →