Spinal Tap Case $ operator

Spinal Tap Case $ operator
0

#1

I have a question about the Spinal Tap Case challenge.

The solution says to insert a blank before upper case letters like this:
str = str.replace(/([a-z])([A-Z])/g, '$1 $2');

I try to understand how this works, but I just don’t get it. What does $ do? Why the 1 and 2 in $1 and $2? Which part is the space to be inserted, is it the one between $1 and $2? How does regexp know to insert it before [A-Z]? Shouldn’t the [A-Z] be preceded by ?= to mean lookbehind?

And what is the name of that $ operator? Googling isn’t being helpful even though I’ve searched for three hours.

Thanks for your help.


#2

$1 and $2 are parenthesized submatches, where $1 is the string/character caught by the range in the first parentheses ([a-z]) and $2 is the match caught by second part ([A-Z]) of the regex. If you have more parentheses, you can use $3, $4 etc.

So… with this expression you can catch chunks of two characters where the first one is lowercase and the second one is uppercase. As these ranges are between parentheses, you can use them in your replace() function’s second argument.

let str = 'lowerAndUppercase'
str.replace(/([a-z])([A-Z])/g, '$1 $2')

In the above example, the regex catches rA and dU.

You could also use a function as the second parameter instead of the $1 $2 string:

let str = 'lowerAndUppercase'
str.replace(/([a-z])([A-Z])/g, function(match, s1, s2) {
  return s1 + '  ' + s2
})

In this case s1 and s2 are the same as $1 and $2 but you have more options to play with them.

I really hope it helps. :wink:


#3

Brilliant!!! I get it now :slight_smile:


#4
function spinalCase(str) {
  // "It's such a fine line between stupid, and clever."
  // --David St. Hubbins
  var nStr = '';
  for(let i = 0; i < str.length; i++) {
    if(/[A-Z]/.test(str[i])) {
      nStr += " " + str[i];
    } else {
      nStr += str[i];
    }
  }
  let arr = [];
  nStr.trim().replace(/_|-/g, " ").split(/\W+/g).forEach(function(ele) {
    arr.push(ele.toLowerCase());
  })
 
  return  arr.join("-");
}