Regex to Convert camelCase to snake_case
Regex pattern to convert camelCase identifiers to snake_case. Handles consecutive capitals (XMLHttpRequest), digits, and PascalCase. Useful for codebase migrations.
Detailed Explanation
camelCase to snake_case
Converting camelCase to snake_case is a frequent step when migrating between languages or naming conventions (JavaScript camelCase to Python snake_case, for example).
Basic Conversion
str.replace(/([a-z0-9])([A-Z])/g, "$1_$2").toLowerCase()
Inserts an underscore between a lowercase or digit and the next uppercase letter, then lowercases everything.
Handle Consecutive Capitals
The basic version turns XMLHttpRequest into x_m_l_http_request. To get xml_http_request:
str
.replace(/([A-Z]+)([A-Z][a-z])/g, "$1_$2")
.replace(/([a-z0-9])([A-Z])/g, "$1_$2")
.toLowerCase()
The first replace splits runs of capitals before a capital-then-lowercase boundary; the second handles the standard case.
Tested Examples
| Input | Basic | Two-Pass |
|---|---|---|
fooBar |
foo_bar |
foo_bar |
getUserName |
get_user_name |
get_user_name |
URLPath |
u_r_l_path |
url_path |
XMLHttpRequest |
x_m_l_http_request |
xml_http_request |
PascalCase |
pascal_case |
pascal_case |
apiV2Endpoint |
api_v2_endpoint |
api_v2_endpoint |
Convert to kebab-case Instead
Replace the underscore with a hyphen:
str.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase()
Handle Numbers Adjacent to Letters
If you want apiV2 to become api_v_2 (separating letter from digit), add a third pass:
str.replace(/([a-zA-Z])(\d)/g, "$1_$2")
Practical Recommendation
For simple identifiers, the two-pass version handles every realistic input correctly. For database column migrations, write tests covering acronyms (URL, API, HTTP), digits, and pre-existing underscores.
Use Case
Migrating a JavaScript codebase’s camelCase API to a Python backend that expects snake_case, or converting database column names during a Rails-to-Django port.