Spinal Tap Case - better way to do this?

Is there a better way to solve the Spinal Tap Case by possibly combining each step into fewer lines? I’m sure changing the value of the str variable 3 times probably isn’t best practice.

function spinalCase(str) {
  str = str.replace(/([a-z])([A-Z])/g, '$1 $2'); // add space between lowercase to uppercase
  str = str.replace(/\W|_/g,'-');// change non letters to -
  str = str.toLowerCase(str.replace(/\W|_/g,'-'));// make it all lowercase
  return str;
}
1 Like

How about chaining the function calls? Then do something like

return str.replace(...).replace(...).replace(...);

iirc there’s a one-liner posted somewhere in this forum that uses just one replace call

1 Like

You don’t need the str.replace(/\W|_/g,'-') here.
As far as chaining it all into a single line - six of one/half dozen of the other. I personally prefer not to.

1 Like

Why do you use the same regex twice on line 3 and 4? It’s also worth checking the documentation of toLowerCase(). Anyway, a shorter solution would be:

Spoiler
function spinalCase(str) {
  str = str.replace(/([a-z])([A-Z])/g, '$1 $2').replace(/\W|_/g,'-')
  return str.toLowerCase()
}

console.log(spinalCase('This Is Spinal Tap'))
console.log(spinalCase('thisIsSpinalTap'))
console.log(spinalCase('The_Andy_Griffith_Show'))
console.log(spinalCase('Teletubbies say Eh-oh'))
console.log(spinalCase('AllThe-small Things'))

You can even make it a one-liner by chaining them:

Spoiler
function spinalCase(str) {
  return str.replace(/([a-z])([A-Z])/g, '$1 $2').replace(/\W|_/g,'-').toLowerCase()
}
1 Like

My original solution didn’t have the repeated regex on line 4 after the toLowerCase, I think I was trying to figure out how to string them together on my own and forgot to delete it before copying into the forum question.

I like the one liner solutions with stringing them all together. That’s what I was looking for but wasn’t sure how exactly you could do it with multiple replace calls. Thanks for the help everyone!

Another way, better or not, would be to use split with a somewhat complex regex:

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

+1 for efficiency
-1 for readability
(The story of regex ;))

1 Like

@ArielLeslie, you said you prefer doing it on multiple lines, would you do it like I originally did by changing the value of the str variable each time? Or is there another way to do it on multiple lines?

My solution looks very like yours

function spinalCase(str) {
  // convert (lowercase)(uppercase) to (lowercase)-(uppercase)
  str = str.replace(/([a-z])([A-Z])/g, "\$1-\$2" );
  // convert spaces and underscores to dashes
  str = str.replace(/[\s_]/g, "-");
  // lowercase
  str = str.toLowerCase();
  return str;
}
3 Likes

Well, it can be broken to multiple lines:

function spinalCase(str) {
  return str.replace(/([a-z])([A-Z])/g, '$1 $2')
    .replace(/\W|_/g,'-')
    .toLowerCase()
}
1 Like

very smart Velenir! i like the idea to split then join! cheers

I reviewed positive and negative lookahead to pass this challenge and here is my workaround:


function spinalCase(str) {
  // "It's such a fine line between stupid, and clever."
  // --David St. Hubbins
  // first, I split the string to make it an array of substrings \W = [A-Za-z-0-9],(?=[A-Z])=positive lookahaed . 
    str=str=str.split(/\W|_|(?=[A-Z])/g).join("-").toLowerCase();
   
    return str;
}

spinalCase('This Is Spinal Tap');