Skip to the code
cf.

camelCase, snake_case, and kebab-case

Write three functions that convert text to a naming style: camelCase(text), snakeCase(text), and kebabCase(text). They accept text in any style, or a mix of styles, so each needs to find the words first.

A word is a run of letters and digits; letters include accented ones like é and û. Every other character (spaces, -, _, ., and so on) separates words, and several in a row count as one boundary.

Inside a run of letters and digits, a new word starts at an uppercase letter that follows a lowercase letter or a digit (backgroundColor, version2Beta), and at the last capital of a run of capitals that's followed by a lowercase letter (XMLHttpRequest is XML, Http, Request). A digit stays in the word it follows: html5 and top10 are single words.

camelCase writes the first word in lowercase and each later word with an uppercase first letter and the rest lowercase, with nothing between them. snakeCase writes every word in lowercase, joined with _, and kebabCase writes them in lowercase, joined with -. Text with no words gives "".

camelCase("background-color"); // "backgroundColor"
snakeCase("XMLHttpRequest");   // "xml_http_request"
kebabCase("FOO_BAR baz");      // "foo-bar-baz"
camelCase("version2 beta");    // "version2Beta"

What the tests check

  1. converts space-separated words to each style
    expect(camelCase("hello big world")).toBe("helloBigWorld");
    expect(snakeCase("hello big world")).toBe("hello_big_world");
    expect(kebabCase("hello big world")).toBe("hello-big-world");
    
  2. splits camelCase and PascalCase humps
    expect(kebabCase("backgroundColor")).toBe("background-color");
    expect(snakeCase("FirstName")).toBe("first_name");
    expect(camelCase("FirstName")).toBe("firstName");
    
  3. treats any run of separators as one boundary
    expect(camelCase("--foo_bar  baz-")).toBe("fooBarBaz");
    expect(snakeCase("foo--bar__baz.qux")).toBe("foo_bar_baz_qux");
    expect(kebabCase(" foo / bar ")).toBe("foo-bar");
    
  4. keeps a run of capitals together as one word
    expect(kebabCase("XMLHttpRequest")).toBe("xml-http-request");
    expect(snakeCase("userID")).toBe("user_id");
    expect(camelCase("parseHTMLString")).toBe("parseHtmlString");
    
  5. lowercases words written in capitals
    expect(camelCase("FOO_BAR")).toBe("fooBar");
    expect(kebabCase("FOO BAR")).toBe("foo-bar");
    expect(camelCase("hello WORLD")).toBe("helloWorld");
    
  6. keeps digits in the word they follow
    expect(kebabCase("version2Beta")).toBe("version2-beta");
    expect(snakeCase("html5 parser")).toBe("html5_parser");
    expect(camelCase("top 10 list")).toBe("top10List");
    
  7. counts accented letters as letters
    expect(kebabCase("crèmeBrûlée")).toBe("crème-brûlée");
    expect(camelCase("crème brûlée")).toBe("crèmeBrûlée");
    expect(snakeCase("Ça Va")).toBe("ça_va");
    
  8. returns an empty string when there are no words
    expect(camelCase("")).toBe("");
    expect(snakeCase("  --  ")).toBe("");
    expect(kebabCase("__")).toBe("");
    

Learn more

solution.jsSaved in this browser

Run tests runs every test on your code, here in your browser. The problem is solved when they all pass.

Ctrl + Enter runs the tests (⌘ + Enter on a Mac).