Skip to content Skip to sidebar Skip to footer

Regular Rxpression To Convert A Camel Case String Into Kebab Case

function hyphenate(str) { var replace = '-'; str = str.toLowerCase().replace(/[\s_\b]/g, replace); console.log(str); return str; } hyphenate('This Is Hyphenate'); // thi

Solution 1:

Note that \b in your [\s_\b] means a backspace character. Not sure you really need this.

Updated answer using the lookbehind feature introduced in ECMAScript 2018:

const re = /[\W_]+|(?<=[a-z0-9])(?=[A-Z])/g;
const strs = ['camelCaseString','This      Is Hyphenate','This_Should_Hyphenate', '09Report'];
strs.forEach(str => 
  console.log( str.replace(re, "-").toLowerCase() )
);

The [\W_]+|(?<=[a-z0-9])(?=[A-Z]) regex will match

  • [\W_]+ - any 1+ non-word and _ chars
  • | - or
  • (?<=[a-z0-9])(?=[A-Z]) - a location between a lowercase ASCII letter/digit and an uppercase ASCII letter.

Old answer

I'd use a bit different logic: add a hyphen before each capital letter inside a word, and then replace and turn lowercase:

var re = /[\s_]+|([a-z0-9])(?=[A-Z])/g; 
var str = 'camelCaseString<br/>This      Is Hyphenate<br/>This_Should_Hyphenate';
var result = str.replace(re, "$1-").toLowerCase();
document.body.innerHTML += result;

Explanation:

  • [\s_]+ - one or more whitespaces or underscores
  • | - or...
  • ([a-z0-9]) - (Group 1) a lowercase letter or digit (since \B would not let us match an uppercase letter after _, add A-Z if you want to add - before each uppercase letter)
  • (?=[A-Z]) - a test for an uppercase ASCII letter (that is not consumed since it (?=[A-Z]) is a lookahead, a zero width assertion).

Solution 2:

Try a lookahead before lowercasing:

function hyphenate(str) {
  return str.split(/[\s_\b]|(?=[A-Z])/).join('-').toLowerCase();
}

Solution 3:

You can use capture groups to get the lowercase followed by the upper case letter, and then convert the whole string to lowercase:

str.replace(/([a-z])([A-Z])/g,"$1-$2").toLowerCase();

Solution 4:

This maybe overkill to your requirements, but hopefully this answer will help anyone who is trying to convert (almost) any string into kebab case:

const convertStringToKebebCase = str => str && str
  .match(/[0-9]{1,}(?=\b)|[A-Z]{2,}(?=[A-Z][a-z]+|[0-9]|\b|_)|[A-Z]?[a-z]+|[A-Z]|[0-9]+/g)
  .map(x => x.toLowerCase())
  .join('-')

Here are the tests for the above function so you can work out how it behaves (I renamed the function to toKebeb just to make it easier to read here):

// Lowercase
expect(toKebeb('path')).toEqual('path')
expect(toKebeb('PATH')).toEqual('path')

// Spaces
expect(toKebeb('path route')).toEqual('path-route')
expect(toKebeb('path route 0')).toEqual('path-route-0')
expect(toKebeb('123 path 4 route 567')).toEqual('123-path-4-route-567')

// Kebab
expect(toKebeb('path-route')).toEqual('path-route')
expect(toKebeb('PATH-ROUTE')).toEqual('path-route')
expect(toKebeb('path-route0')).toEqual('path-route-0')
expect(toKebeb('path-route-0')).toEqual('path-route-0')
expect(toKebeb('123-path-4-route-567')).toEqual('123-path-4-route-567')
expect(toKebeb('123-path-4-route-567')).toEqual('123-path-4-route-567')

// Snake
expect(toKebeb('path_route')).toEqual('path-route')
expect(toKebeb('PATH_ROUTE')).toEqual('path-route')
expect(toKebeb('path_route0')).toEqual('path-route-0')
expect(toKebeb('path_route_0')).toEqual('path-route-0')
expect(toKebeb('123_path_4_route_567')).toEqual('123-path-4-route-567')
expect(toKebeb('123_path_4_route_567')).toEqual('123-path-4-route-567')

// Camel
expect(toKebeb('pathRoute')).toEqual('path-route')
expect(toKebeb('pathROUTE')).toEqual('path-route')
expect(toKebeb('pathRoute0')).toEqual('path-route-0')
expect(toKebeb('pathROUTE0')).toEqual('path-route-0')
expect(toKebeb('123path4Route567')).toEqual('123-path-4-route-567')
expect(toKebeb('123path4ROUTE567')).toEqual('123-path-4-route-567')
expect(toKebeb('pathRouteA')).toEqual('path-route-a')
expect(toKebeb('pathRouteABC')).toEqual('path-route-abc')
expect(toKebeb('pathIsARoute')).toEqual('path-is-a-route')

// Other
expect(toKebeb('path-route0')).toEqual('path-route-0')
expect(toKebeb('path-route123')).toEqual('path-route-123')
expect(toKebeb('path1route')).toEqual('path-1-route')
expect(toKebeb('path123route')).toEqual('path-123-route')
expect(toKebeb('123pathRoute')).toEqual('123-path-route')
expect(toKebeb('123PATHRoute')).toEqual('123-path-route')
expect(toKebeb('123pathROUTE')).toEqual('123-path-route')

I mentioned that this function converts almost any string, and that is because of the way numbers are handled may differ for each use case. For example, it would be perfectly reasonable to expect 3dPrinter to return 3d-printer. The regex can be tweaked to support this, but it raises other issues such as how to handle 3dPrinter12, my3dPrinter or se7en (i.e. which number-string order combinations are respected). Supporting such rules would massively increase the number of tests required and there will always be exceptions.

To support the 3dPrinter example, you could add [0-9]{1,}[a-z]{1,}(?=[A-Z]+)| to the start of the regex (after the "/"), but it would break some of the earlier rules.

To learn about how this regex works, checkout the pattern on regexr.


Post a Comment for "Regular Rxpression To Convert A Camel Case String Into Kebab Case"