How do I zero-pad numbers with :substitute using an expression replacement?
Answer
:%s/\v(\d+)/\=printf('%04d', submatch(1))/g<CR>
Explanation
When you need to normalize IDs, ticket numbers, or sequence values, :substitute can do more than plain text replacement. With an expression replacement (\=), Vim evaluates code for each match, so you can transform numbers on the fly instead of running external scripts. This is especially useful in migration files, logs, or config snippets where number width must be consistent.
How it works
:%s/.../.../gruns substitution across the whole buffer and replaces all matches per line\venables very-magic mode so the regex is less escaped(\d+)captures one or more digits as group 1\=...tells Vim to evaluate the replacement as an expressionprintf('%04d', submatch(1))formats the captured number as 4 digits with leading zeros
Because the replacement is computed per match, each number is formatted independently. You can swap %04d to %06d (or any width) without changing the matching logic.
Example
Before:
ID 7
ID 42
ID 105
Run:
:%s/\v(\d+)/\=printf('%04d', submatch(1))/g
After:
ID 0007
ID 0042
ID 0105
Tips
- Use
\=printf('%08X', submatch(1))for uppercase hex formatting - Combine with a narrower pattern (for example
ID\s+\zs\d+) when you only want specific numbers