Reputation: 529
I have a kebabize function which converts camelCase to kebab-case. I am sharing my code. Can it be more optimized? I know this problem can be solved using regex. But, I want to do it without using regex.
const kebabize = str => {
let subs = []
let char = ''
let j = 0
for( let i = 0; i < str.length; i++ ) {
char = str[i]
if(str[i] === char.toUpperCase()) {
subs.push(str.slice(j, i))
j = i
}
if(i == str.length - 1) {
subs.push(str.slice(j, str.length))
}
}
return subs.map(el => (el.charAt(0).toLowerCase() + el.substr(1, el.length))).join('-')
}
kebabize('myNameIsStack')
Upvotes: 36
Views: 35280
Reputation: 21130
I would use something like this.
function kebabize(string) {
// uppercase after a non-uppercase or uppercase before non-uppercase
const upper = /(?<=\P{Uppercase_Letter})\p{Uppercase_Letter}|\p{Uppercase_Letter}(?=\P{Uppercase_Letter})/gu;
// const upper = /(?<=\P{Lu})\p{Lu}|\p{Lu}(?=\P{Lu})/gu; // for short
return string.replace(upper, "-$&").replace(/^-/, "").toLowerCase();
}
const strings = ["myNameIsStack", "HTTPRequestData", "DataX", "Foo6HelloWorld9Bar", "CdÁb", "FooBAR"];
const result = strings.map(kebabize);
console.log(result);
This snippet replaces each uppercase character (\p{Uppercase_Letter}
) before or after a non-uppercase character (\P{Uppercase_Letter}
) with -
followed by the matched uppercase character.
Example: BooBARBaz
» -Boo-BAR-Baz
each B
has either a non-uppercase character before or after it.
After adding the -
characters it removes the -
at the start of the string (if there is any) and downcases the whole string.
Upvotes: 4
Reputation: 338
In case someone needs to separate all caps for e.g
const example1 = 'someExampleString'
const example2 = 'multiWordTogetherXYZ'
function camelToKebabCase(strToChange) {
return strToChange.replace(/(?:^|\.?)([A-Z])/g, (x, y) => '-' + y.toLowerCase()).replace(/^-/, '');
}
console.log(example1, '->', camelToKebabCase(example1)) // some-example-string
console.log(example2, '->', camelToKebabCase(example2)) // multi-word-together-x-y-z
Upvotes: 0
Reputation: 1
Your current implementation does a good job, but there are a few ways to make it more efficient or concise. Here is a slightly optimized version of your function, keeping the core logic but streamlining it a bit:
const kebabize = str => {
let result = ''; // Use a single string to build the result
for (let i = 0; i < str.length; i++) {
let char = str[i];
// Check if the character is uppercase
if (char === char.toUpperCase() && i !== 0) { // Add a dash before uppercase letters, except the first character
result += '-';
}
result += char.toLowerCase(); // Add the lowercase version of the current character to the result
}
return result;
};
console.log(kebabize('myNameIsStack')); // Outputs: my-name-is-stack
Upvotes: 0
Reputation: 11
Here is the solution I came up with:
let resultDiv = document.querySelector(".result");
let camelCase = "thisIsCamelCase";
let kebabCase;
kebabCase = camelCase.split('').map(el=> {
const charCode = el.charCodeAt(0);
if(charCode>=65 && charCode<=90){
return "-" + el.toLowerCase()
}else{
return el;
}
})
return(kebabCase.join(''))
Upvotes: 0
Reputation: 472
Simple solution for older browsers:
var str = 'someExampleString'
var i
function camelToKebab() {
var __str = arguments[0]
var __result = ''
for (i = 0; i < __str.length; i++) {
var x = __str[i]
if(x === x.toUpperCase()) {
__result += '-' + x.toLowerCase()
} else {
__result += x
}
}
return __result
}
console.log(str, '->', camelToKebab(str))
Upvotes: 0
Reputation: 2947
I have a one-liner similar to Marc's but with a simpler Regular Expression and ~20% faster according my benchmark (Chrome 89).
const kebabize = (str) => str.replace(/[A-Z]+(?![a-z])|[A-Z]/g, ($, ofs) => (ofs ? "-" : "") + $.toLowerCase())
const words = ['StackOverflow', 'camelCase', 'alllowercase', 'ALLCAPITALLETTERS', 'CustomXMLParser', 'APIFinder', 'JSONResponseData', 'Person20Address', 'UserAPI20Endpoint'];
console.log(words.map(kebabize));
[A-Z]+(?![a-z])
matches any consecutive capital letters, excluding any capitals followed by a lowercase (signifying the next word). Adding |[A-Z]
then includes any single capital letters. It must be after the consecutive capital expression, otherwise the expression will match all capital letters individually and never match consecutives.
String.prototype.replace
can take a replacer function. Here, it returns the lowercased matched capital(s) for each word, after prefixing a hyphen when the match offset is truthy (not zero - not the first character of the string).
I suspect Marc's solution is less performant than mine because by using replace to insert hyphens and lowercasing the whole string afterwards, it must iterate over the string more than once, and its expression also has more complex look aheads/behind constructs.
Upvotes: 62
Reputation: 12804
Unlike what you might think, the RegEx way of doing this is actually significantly faster! See benchmark.
The function below supports converting both camelCase
and PascalCase
into kebab-case
:
function toKebabCase(str) {
return str.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase();
}
Upvotes: 17
Reputation: 111
Here is my solution:
Works with camelCase and PascalCase:
let words = ['StackOverflow', 'camelCase', 'alllowercase', 'ALLCAPITALLETTERS', 'CustomXMLParser', 'APIFinder', 'JSONResponseData', 'Person20Address', 'UserAPI20Endpoint'];
let result = words.map(w => w.replace(/((?<=[a-z\d])[A-Z]|(?<=[A-Z\d])[A-Z](?=[a-z]))/g, '-$1').toLowerCase());
console.log(result);
/*
Returns:
[
"stack-overflow",
"camel-case",
"alllowercase",
"allcapitalletters",
"custom-xml-parser",
"api-finder",
"json-response-data",
"person20-address",
"user-api20-endpoint"
]
*/
Explanation:
Upvotes: 11
Reputation: 2675
const kebabize = str => {
return str.split('').map((letter, idx) => {
return letter.toUpperCase() === letter
? `${idx !== 0 ? '-' : ''}${letter.toLowerCase()}`
: letter;
}).join('');
}
console.log(kebabize('myNameIsStack'));
console.log(kebabize('MyNameIsStack'));
You can just check every letter is if upperCase or not and replace it.
Upvotes: 33