2026-09-02 · 8 min read
- regex
- text-processing
- portability
Regular-expression matching receives most of the attention, but replacement strings introduce a second grammar. Group references, literal dollar signs, backslashes, and special whole-match tokens differ among JavaScript, Java, Python, .NET, command-line tools, and editors.
Configuration adds more interpreters. A replacement stored in JSON, YAML, a shell command, or a template may be unescaped before the regex engine receives it, so the visible source is not necessarily the runtime value.
Document the two grammars
Record the regex flavor, flags, replacement API, and host-string format. Include one example showing source literals, runtime values, captures, and final output.
- Name groups used by downstream replacement logic.
- Use noncapturing groups for structure when captures are not needed.
- Avoid relying on engine-specific whole-match tokens in shared rules.
- State whether the API replaces one match or all matches.
Control escaping at each boundary
Escape for one interpreter at a time, beginning with the replacement value the regex API must receive. Then encode that value for source code or configuration. This avoids adding backslashes by trial and error.
When patterns or replacements come from users, distinguish literal search-and-replace from expert regex mode. Escape literal input and constrain expert mode with input limits, timeouts where available, and clear previews.
Prefer code for conditional transformations
A replacement callback or function is clearer when output depends on optional groups, normalization, case changes, or lookup data. It also avoids many special replacement tokens.
Callbacks still need an explicit contract for unmatched groups, offsets, Unicode, and zero-length matches. Avoid mutating external state because global replacement order and retry behavior can surprise callers.
- Keep pure transformations deterministic.
- Validate group presence before formatting output.
- Advance safely after zero-length matches.
- Cap input and output growth for untrusted text.
Test output, not only matches
Use Flashman's regex tester to inspect groups, diff to compare complete output, JSON formatter for configuration escape layers, case converter for naming migrations, and Markdown editor to preserve readable test tables.
Cover literal dollars and backslashes, numbered and named groups, optional and repeated captures, Unicode, multiline text, zero-length matches, output expansion, first-versus-global behavior, and every production engine.