/^/
EasyProgramming3 min read

Python Identifier Regex

Validates that a string is a syntactically legal Python identifier: it must start with an ASCII letter or underscore, followed by any number of letters, digits, or underscores.

#python#identifier#programming#variable#syntax

Regex Pattern

^[A-Za-z_][A-Za-z0-9_]*$

Pattern Breakdown

Hover over a token to see what it does.

^[A-Za-z_][A-Za-z0-9_]*$
TokenMeaning
^Anchors the match to the start of the string
[A-Za-z_]The identifier must begin with an uppercase letter, lowercase letter, or underscore
[A-Za-z0-9_]*Zero or more letters, digits, or underscores make up the rest of the identifier
$Anchors the match to the end of the string, ensuring the whole string is a valid identifier

Detailed Explanation

What it does

This pattern checks whether a string is shaped like a valid Python identifier: variable, function, class, or module name. It requires the first character to be a letter or underscore and every following character to be a letter, digit, or underscore, with no spaces, hyphens, or punctuation anywhere in the string.

Why it works

Python's grammar defines an identifier as starting with an ASCII letter or underscore and continuing with any mix of letters, digits, and underscores. The two character classes mirror that rule directly, and the ^/$ anchors force the entire input to satisfy it rather than just a substring, so something like foo-bar or 2fast is correctly rejected.

Common use cases

  • Validating variable, function, or class names in a code generator or template engine
  • Checking that a config key or CLI argument name can be used as a Python keyword argument
  • Linting auto-generated column or field names before they are turned into Python attributes
  • Sanitizing user-supplied strings before using them as dynamic attribute names via setattr

Edge cases

  • A single underscore, _, is a fully valid identifier and matches
  • Identifiers with trailing digits, like value2, are valid since digits are allowed anywhere after the first character
  • Python 3 actually permits many Unicode letters in identifiers (e.g. café), which this ASCII-only pattern intentionally rejects
  • Reserved words like class or def match this pattern structurally even though they cannot be used as identifiers in real Python code

Limitations

  • Does not exclude Python keywords (class, def, return, etc.), which are structurally valid but semantically illegal identifiers
  • Only covers the ASCII subset of legal identifier characters and ignores Python 3's Unicode identifier support
  • Does not check identifier length limits or naming-convention style (snake_case vs camelCase)

Interactive Tester

Edit the pattern or text below — matching runs live in your browser.

variable _private camelCase2

Test Cases

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

InputExpectedResult
Pass
Pass
Pass
Pass
Pass
Pass
Pass
Pass
Pass

Language Variants

Production-ready examples in 12 languages.

const pythonIdentifierRegex = /^[A-Za-z_][A-Za-z0-9_]*$/;
console.log(pythonIdentifierRegex.test('my_variable_2')); // true

Common Mistakes

Assuming this regex also rejects reserved keywords like class or import, since they look like normal identifiers

Fix: Cross-check the matched string against Python's keyword.kwlist (or the keyword module) in addition to the regex

Using \w+ alone (e.g. ^\w+$) and forgetting it allows an identifier to start with a digit like 123abc

Fix: Split the first character into its own [A-Za-z_] class separate from the repeating [A-Za-z0-9_]* tail

Expecting this ASCII-only pattern to accept Unicode identifiers such as café or变量, which real Python 3 allows

Fix: For full spec compliance use Python's own str.isidentifier() method instead of a hand-written regex

Performance Notes

  • The two character classes are mutually exclusive in what they consume, so the engine runs in linear time with no catastrophic backtracking
  • Anchoring with ^ and $ allows invalid strings to fail immediately on the first character
  • Cheap enough to run on every token while parsing or linting large codebases without noticeable overhead

Browser Compatibility

EngineSupportedNotes
ChromeYes
FirefoxYes
SafariYes
EdgeYes
Node.jsYes