/^/
EasyProgramming4 min read

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.

#snakecase#programming#identifier#naming-convention#variable

Regex Pattern

^[a-z][a-z0-9]*(?:_[a-z0-9]+)*$

Pattern Breakdown

Hover over a token to see what it does.

^[a-z][a-z0-9]*(?:_[a-z0-9]+)*$
TokenMeaning
^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.

snake_case variable_name_123 snake

Test Cases

Editable — add your own inputs to see if they pass.

InputExpectedResult
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')); // true

Common 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

EngineSupportedNotes
ChromeYes
FirefoxYes
SafariYes
EdgeYes
Node.jsYes