snake_case Identifier Regex
Validates that a string is a lower_snake_case identifier: lowercase words separated by single underscores, with no leading, trailing, or doubled underscores.
Regex Pattern
^[a-z][a-z0-9]*(?:_[a-z0-9]+)*$Pattern Breakdown
Hover over a token to see what it does.
| Token | Meaning |
|---|---|
| ^ | Anchors the match to the start of the string |
| [a-z] | The identifier must begin with a lowercase letter |
| [a-z0-9]* | Zero or more lowercase letters or digits completing the first word |
| (?: | Start of a non-capturing group for each additional underscore-separated word |
| _[a-z0-9]+ | An underscore followed by at least one lowercase letter or digit for the next word |
| )* | Closes the group and allows any number of additional words |
| $ | Anchors the match to the end of the string |
Detailed Explanation
What it does
This pattern checks that a string follows lower_snake_case naming: it must start with a lowercase letter, and every additional word is introduced by a single underscore followed by at least one lowercase letter or digit. Strings with uppercase letters, dashes, spaces, or double underscores are rejected.
Why it works
The leading [a-z][a-z0-9]* requires the identifier to open with a lowercase run, and the repeating group (?:_[a-z0-9]+)* only accepts an underscore when it's immediately followed by at least one word character, which is what rules out double underscores (an empty word between two underscores can't satisfy the + quantifier). The ^/$ anchors guarantee the whole string conforms, not just a substring.
Common use cases
- Linting Python or Ruby variable and function names against snake_case style guides
- Validating database column names or environment variable keys before use
- Enforcing consistent naming in code generators or ORMs that map to snake_case schemas
- Detecting camelCase or kebab-case names that should be converted to snake_case
Edge cases
- A single lowercase word with no underscore, like 'variable', is valid since the repeating group is optional
- Trailing digits, like 'value_1', are valid because digits are allowed within any word segment
- A leading underscore, like '_private', is rejected since the first character must be a lowercase letter, not an underscore
- Consecutive underscores, like 'snake__case', are rejected because an underscore must be immediately followed by at least one word character
Limitations
- Does not support SCREAMING_SNAKE_CASE constants, which use uppercase letters instead
- Does not support Unicode letters outside the basic a-z/0-9 ranges
- Cannot verify that the identifier is a valid, non-reserved word in a specific programming language
Interactive Tester
Edit the pattern or text below — matching runs live in your browser.
Test Cases
Editable — add your own inputs to see if they pass.
| Input | Expected | Result | |
|---|---|---|---|
| Pass | |||
| Pass | |||
| Pass | |||
| Pass | |||
| Pass | |||
| Pass | |||
| Pass | |||
| Pass |
Language Variants
Production-ready examples in 12 languages.
const snakeCaseRegex = /^[a-z][a-z0-9]*(?:_[a-z0-9]+)*$/;
console.log(snakeCaseRegex.test('variable_name_123')); // trueCommon Mistakes
Writing [a-z0-9_]+ to 'match snake_case', which also accepts leading/trailing/doubled underscores like '_foo__bar_'
Fix: Structure the pattern as a required first word plus repeated (?:_[a-z0-9]+)* groups so underscores must be internal single separators
Forgetting to allow digits within words, causing valid identifiers like 'value_2' to be rejected
Fix: Include 0-9 in each word's character class, e.g. [a-z0-9]* and [a-z0-9]+
Using this pattern to also validate SCREAMING_SNAKE_CASE constants
Fix: Write a separate pattern like ^[A-Z][A-Z0-9]*(?:_[A-Z0-9]+)*$ for uppercase constant naming
Performance Notes
- Both quantified segments are non-overlapping character classes, so the engine matches in linear time with no catastrophic backtracking
- Anchoring with ^ and $ lets invalid identifiers fail fast on the very first character check
- Cheap enough to run per-keystroke in an editor, linter, or form validator without noticeable cost
Browser Compatibility
| Engine | Supported | Notes |
|---|---|---|
| Chrome | Yes | — |
| Firefox | Yes | — |
| Safari | Yes | — |
| Edge | Yes | — |
| Node.js | Yes | — |
Work with this pattern
Take this expression further — test it against your own data, adapt it in the builder, or read up on the syntax behind it.
Regex Tester
Test a regular expression against sample text and see every match highlighted live.
Regex Generator
Build a pattern by clicking blocks — no syntax memorisation required.
Regular Expressions Guide
What regex is, how the syntax works, and the mistakes that trip people up.
Regex Cheat Sheet
Every token, quantifier, and assertion on one printable page.
Python Regex Guide
The re module end to end — search, match, findall, groups, and substitution.
Regex Pattern Library
100+ ready-to-use patterns for email, URLs, dates, IPs, and more.