Matching Alphanumeric Strings with Regular Expressions
"Alphanumeric" means letters plus digits — no spaces, no punctuation, no accented characters. It's one of the most common validation rules in web apps: for usernames, product SKUs, API keys, coupon codes, and slugs. Below are the patterns developers reach for every day, with clear rules about what they accept and reject.
The Core Patterns
Strict alphanumeric (ASCII only)
/^[a-zA-Z0-9]+$/ // one or more letters or digits
/^[a-zA-Z0-9]*$/ // same, but empty string also accepted
/^[a-z0-9]+$/i // same, using i flag for case insensitivity
/^[0-9A-Za-z]+$/ // order in character class doesn't matter[a-zA-Z0-9]is the classic alphanumeric character class. It rejects everything that isn't an ASCII letter or digit — spaces, hyphens, punctuation, accented characters, and emoji.
Alphanumeric with spaces
/^[a-zA-Z0-9 ]+$/ // add literal space to class
/^[a-zA-Z0-9\s]+$/ // \s = any whitespace (space, tab, newline)
/^[a-zA-Z0-9]+( [a-zA-Z0-9]+)*$/ // words separated by single spaces onlyThe last pattern rejects strings with leading, trailing, or consecutive spaces — good for "words separated by single spaces" validation.
Alphanumeric with common punctuation
/^[a-zA-Z0-9_]+$/ // add underscore (matches \w in ASCII mode)
/^[a-zA-Z0-9_-]+$/ // + hyphen (must be at start or end of class)
/^[a-zA-Z0-9._-]+$/ // + dot, underscore, hyphen (common for slugs)
/^\w+$/ // shorthand for [A-Za-z0-9_]Length-constrained alphanumeric
/^[a-zA-Z0-9]{3,20}$/ // 3-20 characters
/^[a-zA-Z0-9]{8,}$/ // 8 or more characters (min-length only)
/^[a-zA-Z0-9]{,20}$/ // 0-20 characters (max-length only)
/^[a-zA-Z0-9]{16}$/ // exactly 16 charactersUnicode-aware alphanumeric
/^[\p{L}\p{N}]+$/u
// \p{L} matches every Unicode letter (Latin, Cyrillic, Greek, Arabic, CJK…)
// \p{N} matches every Unicode digit (Arabic-Indic, Devanagari, etc.)
// Requires the u flag in JavaScript. Python's \p{L} needs the regex library, not re.Language-Specific Usage
JavaScript
const ALPHA_NUM = /^[a-zA-Z0-9]+$/;
function isAlphanumeric(str) {
return ALPHA_NUM.test(str);
}
isAlphanumeric('Abc123'); // true
isAlphanumeric('abc'); // true (all letters)
isAlphanumeric('123'); // true (all digits)
isAlphanumeric('Hello World'); // false (has space)
isAlphanumeric('ñoño'); // false (accented)
isAlphanumeric(''); // false (+ requires at least 1)
// Strip non-alphanumeric from a string
'Hello, World! 123'.replace(/[^a-zA-Z0-9]/g, '');
// → 'HelloWorld123'
// Unicode-aware version
const UNI_ALPHA_NUM = /^[\p{L}\p{N}]+$/u;
UNI_ALPHA_NUM.test('ñoño123'); // truePython
import re
ALPHA_NUM = re.compile(r'^[a-zA-Z0-9]+$')
def is_alphanumeric(s: str) -> bool:
return bool(ALPHA_NUM.match(s))
is_alphanumeric('Abc123') # True
is_alphanumeric('café') # False (é is not ASCII)
# Python has a built-in that's cleaner for pure alphanumeric:
'Abc123'.isalnum() # True
'Hello World'.isalnum() # False (space)
'ñoño'.isalnum() # True (Python's isalnum IS Unicode-aware)
# Strip non-alphanumeric
re.sub(r'[^a-zA-Z0-9]', '', 'Hello, World! 123')
# → 'HelloWorld123'PHP
function isAlphanumeric(string $s): bool {
return (bool) preg_match('/^[a-zA-Z0-9]+$/', $s);
}
// PHP also has ctype_alnum which is faster than regex:
ctype_alnum('Abc123'); // true
ctype_alnum('Hello World'); // false
// Strip non-alphanumeric
preg_replace('/[^a-zA-Z0-9]/', '', 'Hello, World! 123');
// → 'HelloWorld123'Common Pitfalls
\w is not the same as alphanumeric
\w matches [A-Za-z0-9_]— it INCLUDES the underscore. If your rule is "letters and digits only, no underscore", use [a-zA-Z0-9] explicitly. Also, in some engines with Unicode mode, \w matches accented letters too.
Hyphen inside a character class is a range operator
[a-zA-Z0-9-_] works because - is at the end. But [a-z-A] tries to build a range from z to A and fails silently in some engines. Always put hyphens at the start or end of the class, or escape them: [a\-z].
Empty strings pass with *
/^[a-zA-Z0-9]*$/ accepts empty strings. If you require at least one character, use + instead of *.
ASCII-only will reject international names
[a-zA-Z0-9] rejects José, François, Ünal,О́льга. For anything user-facing (names, addresses, comments), use \p{L}\p{N} with the Unicode flag. Reserve ASCII-only for machine-facing IDs, slugs, and coupon codes.
Locale-specific isalnum in some languages
Python's str.isalnum() is Unicode-aware. PHP's ctype_alnumis ASCII-only. Java's Character.isLetterOrDigitis Unicode-aware. Know which one you're calling.
Alphanumeric Cheatsheet
| Goal | Pattern | Matches |
|---|---|---|
| Strict ASCII | /^[a-zA-Z0-9]+$/ | Abc123, abc, 123 |
| With spaces | /^[a-zA-Z0-9 ]+$/ | Hello World 123 |
| Slug-safe | /^[a-z0-9-]+$/ | my-post-123 |
| Length 3-20 | /^[a-zA-Z0-9]{3,20}$/ | bounded length |
| Unicode | /^[\p{L}\p{N}]+$/u | ñoño123, 你好123 |
Testing Your Alphanumeric Regex
Use the live Regex Tester above with these test strings:
- Match:
Abc123,abc,123,a1B2c3 - Reject (special chars):
hello!,foo@bar,a-b - Reject (space):
Hello World— unless space added to class - Reject (Unicode):
ñoño,café— unless\p{L}used - Reject (empty): empty string — unless
*quantifier used - Edge:
007— accepted as all-digits alphanumeric
Common Mistakes When Writing Alphanumeric Regex
A few recurring pitfalls trip up developers writing alphanumeric validators:
- Using
\wwhen you mean alphanumeric.\wincludes underscore. If underscore is not allowed, use[a-zA-Z0-9]. - Blocking legitimate user data. A strict ASCII-only rule on a name field rejects
José,François,Ünal. Only require ASCII for machine-facing IDs. - Using
*instead of+.*accepts an empty string. If a field is required, use+. - Hyphen in the middle of the class.
[a-zA-Z-0-9]tries to build a range fromZto0and produces surprising matches. Put the hyphen first or last:[-a-zA-Z0-9]or[a-zA-Z0-9-]. - Not stripping vs not validating. If your goal is to accept ANY input and store a cleaned version, use
str.replace(/[^a-zA-Z0-9]/g, '')— don't reject the form and force the user to retype.
Performance Notes
Alphanumeric regexes are among the fastest patterns in every engine — character classes like [a-zA-Z0-9]compile to a single-instruction table lookup. Validating a million strings takes milliseconds. In hot paths, prefer language-native equivalents where available: Python's str.isalnum() and PHP's ctype_alnum() are typically faster than regex and read more clearly. For bulk stripping of non-alphanumeric characters from large text buffers, a compiled regex object beats a Python for-loop by 10-50×.