Regular Expressions Module 6
Lookaround and advanced constructs interview questions
Interview questions on lookaround and advanced constructs: warm-ups, then what each harder question tests and how a good answer starts.
Warm-up questions
Short questions with short answers, each answered in full.
-
Fresher to mid
When should you replace a recursive regex for balanced brackets with a short parser?
Answered in the lesson Conditionals, recursion and PCRE2 extras
-
Fresher to mid
What does "zero-width" mean for a lookahead, and why does an engine still move forward after one?
Answered in the lesson Lookahead: conditions without consuming text
-
Fresher to mid
Why does CPython insist a lookbehind be fixed width, and what does "fixed width" mean exactly?
Answered in the lesson Lookbehind and its limits in each flavour
Questions with model answers
What each question tests, the first step of a good answer and the follow-ups to expect.
-
Mid to senior
A PHP form checks a delivery field with
^(?(?=\d)\d{6}|[A-Z]{2}\d{4})$: a six-digit PIN code, or else a store code such as KA1234. The same rule must run in a Python service and in the browser. Why does neither accept the pattern, and what single pattern gives the same verdicts in all three?- What it tests
- Whether the candidate can read a condition that is an assertion rather than a group, knows which engines accept which conditions, and can prove a portable rewrite keeps every verdict.
- First step
- Name the kind of condition the pattern uses, then check which kinds CPython's conditional accepts and whether JavaScript has conditionals at all. Before writing the port, list inputs on both sides of the condition, such as 560001, KA1234 and 5A1234.
- Follow-ups
-
- What error does each engine give, and what does it tell you?
- When would an alternation accept text that the conditional rejects?
- Which conditions besides a group number can PCRE2 test?
- How do you keep the PHP, Python and browser copies of the rule in step?
From the lesson Conditionals, recursion and PCRE2 extras
Model answer, Pro. Model answers open with any pass; prices are in the notice on this page.Opening the model answers with your pass…
Model answers open with any MySmartCoPilot pass.
- Pro pass · 1 week₹79$2.99
- 30 days₹179$5.99
- 1 year₹1,699$45
One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.
Passes can’t be bought right now, so the model answers can’t be opened at the moment. If you have a pass, enter your licence key.
It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).
In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 4 minutes
-
Mid to senior
A PHP chat-log redactor runs
preg_replace('/ORD-\d+(*SKIP)(*FAIL)|\d{10}/', '[phone]', $line)to mask phone numbers but keep order numbers such as ORD-9123456789. What does it print forORD-9123456789,919876543210andord-9123456789, and how would you port it to Python's re.sub?- What it tests
- Whether the candidate can trace (*SKIP)(*FAIL) inside a replacement, predict where the redactor garbles or loses data, and carry the skip into an engine without verbs.
- First step
- Trace the three inputs one at a time: where does each alternative start matching, which one wins, and what is left of the input after the replacement? Then decide what the port must return for a match it has to keep.
- Follow-ups
-
- What would the redactor do to ORD-9123456789 without (*SKIP)?
- Which phone formats does
\d{10}still miss? - Why does the Python port need a function as the replacement?
- Which test lines should the redactor carry before it runs on real logs?
From the lesson Conditionals, recursion and PCRE2 extras
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 4 minutes
-
Senior to staff
Your CI pipeline runs integration tests against a PHP service. After a container image update, tests that use a recursive pattern for balanced parentheses start failing sporadically. The pattern \((?:[^()]++|(?R))*\) matched in production for two years. What changed, and how do you diagnose and fix it?
- What it tests
- Telling a resource limit from a wrong answer in PHP, the settings and builds that move the limits, how the JIT and the input shape change the failure, and deterministic tests.
- First step
- Log preg_last_error() for a failing input to learn which limit was hit, then compare the old and new images: PCRE_VERSION, pcre.backtrack_limit, pcre.recursion_limit and pcre.jit from php -i.
- Follow-ups
-
- What symptom does a pattern produce when it hits the recursion limit?
- Why can the same input fail with the JIT switched off and pass with it on?
- Why might a working pattern exceed limits only on certain inputs?
- How do you make the test deterministic regardless of PCRE2 defaults?
From the lesson Conditionals, recursion and PCRE2 extras
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 4 minutes
-
Mid to senior
A genomics script counts the motif TATA in a DNA string with
len(re.findall("TATA", seq)). OnTATATATAit reports 2, but the lab's own tool reports 3. Which count is right, why do they differ, and how do you get all three with one pattern in Python and in JavaScript?- What it tests
- Whether the candidate can explain how a search moves on after each match, report overlapping hits with one pattern, and carry the count across engines, Go included.
- First step
- Write down every position where TATA starts in TATATATA, then the position where findall resumes after each match it makes. The gap between the two lists is the bug. Then look for a construct that can test for the motif at a position without consuming it.
- Follow-ups
-
- What does
re.findall("(?=TATA)", seq)return, and why? - What does
matchAllneed in JavaScript, and what happens without it? - How do you count overlapping matches in Go, whose RE2 has no lookahead?
- What does a 1,000-letter run of
ado to the count ofaa?
- What does
From the lesson Lookahead: conditions without consuming text
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 4 minutes
-
Mid to senior
A Python job keeps log lines that mention timeout but not retry with
re.match(r"(?!.*retry).*timeout", line). Its Node port runs/(?!.*retry).*timeout/.test(line)and letsretry after timeoutthrough, yet still dropsdb timeout, retry 1. Explain both results and fix the Node version.- What it tests
- Whether the candidate can trace a lookahead through a search start by start, tell match from search across languages, and fix an exclusion rule for any word order.
- First step
- Run the Node pattern by hand on retry after timeout, one start position at a time: at which position does the negative lookahead first hold, and what can .*timeout match from there? Compare that with the only position re.match ever tries.
- Follow-ups
-
- Why is
db timeout, retry 1still dropped by the unanchored pattern? - Does moving the lookahead after the word, as in
^.*timeout(?!.*retry), fix the rule? - How would a Go service write the same filter without lookaround?
- Which test lines would have caught the bug before the port shipped?
- Why is
From the lesson Lookahead: conditions without consuming text
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 4 minutes
-
Mid to senior
A shared checkout bundle formats rupee amounts with
s.replace(/(?<=\d)(?=(\d\d)*\d{3}$)/g, ","), so 1234567 becomes 12,34,567. On some older iPhones the whole checkout page stops working, not only the amounts. Explain why, and give a fix that prints the same groups everywhere.- What it tests
- Whether the candidate can trace a failure on older browsers to how and when the engine reads a pattern, and rewrite a zero-width insertion portably or hand it to the platform.
- First step
- Ask which engine the failing phones run, and at what moment that engine reads a regex literal compared with the rest of the bundle. Then look for a form of the same insertion that needs no lookbehind.
- Follow-ups
-
- Why does a try and catch around the replace call not save the page?
- How does the rewrite without lookbehind still put every comma in the right place?
- What changes when the amount has paise, as in 1234567.50?
- When is Intl.NumberFormat a better answer than any regex?
From the lesson Lookbehind and its limits in each flavour
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 4 minutes
-
Mid to senior
A PHP job counts empty CSV fields as the commas that follow a comma, with
preg_match_all('/(?<=,),/', $line). A colleague rewrites it aspreg_match_all('/,\K,/', $line), saying\Kescapes lookbehind's limits. Onid,,,,namethe count drops from 3 to 2. Explain the drop, and say when the two forms agree.- What it tests
- Whether the candidate can trace what \K and a lookbehind each consume during a global search, and say when the two forms are interchangeable and when they are not.
- First step
- Write out the four commas of id,,,,name with their offsets and trace both patterns by hand: for every match, note the offset it reports and the offset where the next attempt begins.
- Follow-ups
-
- Which offsets does each form report on
id,,,,name? - Which engines can run each form, and what would a Go job use?
- When does
\Kreally beat a lookbehind? - How would you test a refactor between the two forms so a drop like this cannot ship?
- Which offsets does each form report on
From the lesson Lookbehind and its limits in each flavour
Model answer, Pro.In the answer:
- Model answer
- Follow-up answers
- Common mistakes
- Rubric
- Variants
- about 4 minutes
All Regular Expressions interview questions · The Regular Expressions track