FCC Bonfire Series 129: Spinal Tab Case

Hello campers of young and old, today, we are going to be converting strings to spinal-tab-case. If you did not know about spinal-tab-case, well, you do now. You just-saw-it-twic… thrice!

Spinal case simply removes all spaces and sets dashes instead, while having the string be all lower-case characters. It sounds easy to achieve, we are replace wizards after all; but we’ll see that some cases might not be so straightforward.

First thing that comes to mind is probably:

function spinalCase(str) {
  return str.replace(/ /g, '-').toLowerCase();
}

We first replace all spaces with dashes, and then get rid of capital letters. And you see, that works for strings such as:

spinalCase('Hello world!'); //-> hello-world!

spinalCase('I want to see the world BURN.'); //-> i-want-to-see-the-world-burn.

But how about these other case?

spinalCase('Hey_I_got_you_this_time'); //-> hey_I_got_you_this_time

Let’s get rid of those underscores too!

function spinalCase(str) {
  return str.replace(/[ _]/g, '-').toLowerCase();
}

I just replaced the single space in out regular expression and put this in its place: [ _]. There is actually an underscore and a space in between those brackets! But we are not there yet! You see, we could get a string such as: HahaYouStillFailAtSpinalTabCase! And this guy will have us use our brains for a little bit.

First of all, I’ll let you know that we can use RegExp capturing groups, a capturing group is nothing but a set of parenthesis that surround a regular expression, and they allow us to access the text that they have matched using $1, $2 etc. Here’s an example:

var sampleText = 'hello28';

sampleText.replace(/([A-z])([0-9])/g, '$1 $2'); //-> hello 28

Let me explain in detail: out regular expression will actually match /[A-z][0-9]/, in other words, a letter followed by a number from 0 to 9. Using the parenthesis, we have access to the first set of these by using $1 in the second argument of the replace method, and to the second set of parenthesis by using $2 (this goes on with $3, $4 and so on). Here’s an step by step explanation of the process:

  • /([A-z])([0-9])/g will match this part of the string: hello28
  • The first capturing group ([A-z]) is: o
  • The second capturing group ([0-9]) is: 2
  • In short, $1 = o and $2 = 2.
  • Replace ‘$1$2’ with ‘$1 $2’. And so, we have put a space between the letter o and the number 2.

Let’s try and apply this new-found knowledge to the task at hand! Remember, we are trying to turn this string into spinal tab case: HahaYouStillFailAtSpinalTabCase. Let’s try to insert a dash character each time we find an uppercase character:

function spinalCase(str) {
  return str.replace(/[ _]/g, '-').replace(/([A-Z])/g, '-$1').toLowerCase();
}

We did it! Did we? Uhmmm, we broke our previous passed tests didn’t we? We are placing dashes in places where we don’t need to! Lets try to constrain our second replace to do it a little better. Let’s match where a lowercase character meets an uppercase character instead, and place a dash in between:

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

That is better! I will stop here. Try to come up with your own versions and see you on the next bonfire!