camelCase to snake_case in JavaScript

s.replace(/([A-Z]+)([A-Z][a-z])/g, '$1_$2').replace(/([a-z\d])([A-Z])/g, '$1_$2').toLowerCase()

That line turns HTTPServer into http_server and getHTTP2Client into get_http2_client. The first replace splits a run of capitals before its last capital when a lowercase letter follows, so HTTPServer becomes HTTP_Server. The second puts an underscore between a lowercase letter or digit and the capital after it. Then everything is lowercased.

const toSnake = (s) =>
  s.replace(/([A-Z]+)([A-Z][a-z])/g, '$1_$2').replace(/([a-z\d])([A-Z])/g, '$1_$2').toLowerCase();

for (const name of ['HTTPServer', 'getHTTPResponseCode', 'userID', 'XMLHttpRequest', 'sha256Hash', 'getHTTP2Client']) {
  console.log(name.padEnd(20), toSnake(name));
}
HTTPServer           http_server
getHTTPResponseCode  get_http_response_code
userID               user_id
XMLHttpRequest       xml_http_request
sha256Hash           sha256_hash
getHTTP2Client       get_http2_client

The tool below converts the same six names, one per line, and its snake_case row matches.

The naive version

'HTTPServer'.replace(/[A-Z]/g, (c) => '_' + c.toLowerCase());          // '_h_t_t_p_server'
'userID'.replace(/[A-Z]/g, (c) => '_' + c.toLowerCase());              // 'user_i_d'
'HTTPServer'.replace(/([a-z])([A-Z])/g, '$1_$2').toLowerCase();       // 'httpserver'

An underscore before every capital breaks acronyms apart and adds a leading underscore to PascalCase names. Splitting only where a lowercase letter meets a capital goes wrong the other way and glues HTTPServer into one word. It takes both patterns.

Digits and other letters

[a-z\d] lets a digit end a word, so sha256Hash keeps sha256 together. A digit never starts one: parseHTTPResponse2xx gives parse_http_response2xx, while the tool below treats 2xx as its own word and writes parse_http_response_2xx.

[A-Z] and [a-z] are ASCII only, so caféBar comes out as cafébar. With the u flag, Unicode property classes fix that:

const toSnakeUnicode = (s) =>
  s.replace(/(\p{Lu}+)(\p{Lu}\p{Ll})/gu, '$1_$2').replace(/([\p{Ll}\d])(\p{Lu})/gu, '$1_$2').toLowerCase();
toSnakeUnicode('caféBar');   // 'café_bar'
toSnakeUnicode('naïveÉtat'); // 'naïve_état'

Libraries split differently

lodash 4’s _.snakeCase keeps acronyms together but makes every number a word of its own and strips accents. change-case 5’s snakeCase gives the same results as the two patterns for the six names above:

_.snakeCase('getHTTP2Client'); // 'get_http_2_client'
_.snakeCase('sha256Hash');     // 'sha_256_hash'
_.snakeCase('caféBar');        // 'cafe_bar'
snakeCase('getHTTP2Client');   // 'get_http2_client', from change-case

If two systems must agree on column or field names, make them use the same function.

The reverse: snake_case to camelCase

const toCamel = (s) => s.replace(/_([a-z\d])/g, (_, c) => c.toUpperCase());
toCamel('get_http2_client'); // 'getHttp2Client'
toCamel('http_server');      // 'httpServer'

Acronyms don’t survive the round trip: HTTPServer goes to http_server and comes back as httpServer. lodash’s _.camelCase('http_server') gives the same.

Try it in the Case Converter

16 words: HTTP · Server · get · HTTP · Response · Code · user · ID · XML · Http · Request · sha256 … and 4 more

  • camelCasewords run together, each after the first capitalized
    httpServer getHttpResponseCode userId xmlHttpRequest sha256Hash getHttp2Client
  • PascalCaseevery word capitalized, run together
    HttpServer GetHttpResponseCode UserId XmlHttpRequest Sha256Hash GetHttp2Client
  • snake_caselower case, joined with underscores
    http_server get_http_response_code user_id xml_http_request sha256_hash get_http2_client
  • kebab-caselower case, joined with hyphens
    http-server get-http-response-code user-id xml-http-request sha256-hash get-http2-client
  • CONSTANT_CASEupper case, joined with underscores
    HTTP_SERVER GET_HTTP_RESPONSE_CODE USER_ID XML_HTTP_REQUEST SHA256_HASH GET_HTTP2_CLIENT
  • Title Casea, an, and, of, the, to, in, on, for and or stay lower unless first or last
    Http Server Get Http Response Code User Id Xml Http Request Sha256 Hash Get Http2 Client
  • Sentence casethe first word capitalized, the rest lower
    Http server Get http response code User id Xml http request Sha256 hash Get http2 client
  • lower caseevery letter lower
    http server get http response code user id xml http request sha256 hash get http2 client
  • UPPER CASEevery letter upper
    HTTP SERVER GET HTTP RESPONSE CODE USER ID XML HTTP REQUEST SHA256 HASH GET HTTP2 CLIENT
  • URL sluglower-case ASCII, accents folded, single hyphens
    http-server-get-http-response-code-user-id-xml-http-request-sha256-hash-get-http2-client

Runs in your browser. Nothing you enter is sent anywhere.