7

I am stuck on this coding challenge Spinal Tap Case from freeCodeCamp. Essentially I don't know how to get the last check to execute.

This is the last check: spinalCase("AllThe-small Things") should return "all-the-small-things"

And this is my code:

function spinalCase(str) {
    var outputString, 
              newstr,
              pattern1 = new RegExp(/[_\s]/, 'g'),
              pattern2 = new RegExp(/(?=[A-Z])/, 'g'),
              stringTest1 = pattern1.test(str),
              stringTest2 = pattern2.test(str);

         if(stringTest1)  {
                outputString = str.replace(pattern1, '-');
                newstr = outputString.toLowerCase();
          } else if(stringTest2) {
               str.split(/(?=[A-Z])/).join(' ');
                outputString = str.replace(pattern2, '-');
                newstr = outputString.toLowerCase();
          } else if (stringTest1 && stringTest2){
                outputString = str.replace(pattern1, '-');
                outputString = str.replace(pattern2, '-');
                newstr = outputString.toLowerCase();
          }

  return newstr;

}

I do realize the last else ifcondition should go first however I didn't get the syntax right.

Thanks in advance!

Antonio Pavicevac-Ortiz
  • 7,239
  • 17
  • 68
  • 141

12 Answers12

7

Here is how I recommend doing it:

function sp(str) {
  var spinal = str.replace(/(?!^)([A-Z])/g, ' $1')
                .replace(/[_\s]+(?=[a-zA-Z])/g, '-').toLowerCase();
  return spinal 
}

JsBin Example

as far as your code, you check for:

if test1 else if test2, then else if test1 and test2, the logic is not correct:

you could try to adding a !test2 or !test1 to the first if checks to get it working:

if (stringTest1 && !stringTest2)...

EDIT:

here is how you can get your code to fire in that last else if, I put a console.log in there to show you here:

JSBin Example

function spinalCase(str) {
    var outputString, 
              newstr,
              pattern1 = new RegExp(/[_\s]/, 'g'),
              pattern2 = new RegExp(/(?=[A-Z])/, 'g'),
              stringTest1 = pattern1.test(str),
              stringTest2 = pattern2.test(str);

         if(stringTest1 && !stringTest2)  {
                outputString = str.replace(pattern1, '-');
                newstr = outputString.toLowerCase();
          } else if(!stringTest1 && stringTest1) {
               str.split(/(?=[A-Z])/).join(' ');
                outputString = str.replace(pattern2, '-');
                newstr = outputString.toLowerCase();
          } else if (stringTest1 && stringTest2){
                console.log('were in the last else!!!');
                outputString = str.replace(pattern1, '-');
                outputString = str.replace(pattern2, '-');
                newstr = outputString.toLowerCase();
          }

  return newstr;

}
omarjmh
  • 13,632
  • 6
  • 34
  • 42
  • —I couldn't figure out how to augment my code with your insight, however I really appreciate your solution. Very elegant. I'll have to dig into your solution. Although I think I get it. I didn't know you can chain methods like that. Thanks so much for your help Jordan! – Antonio Pavicevac-Ortiz Apr 16 '16 at 00:26
  • Thanks so much, but it must be off as it doesn't quite work. The last condition does indeed fire, but overall the function doesn't produce the same result as your answer. Speaking of which do you mind explaining a bit what your solution is doing? My take is the following: First you are using `replace` to check vs. the first expression—which checks for the any uppercase characters `A-Z` but what is `(?!^)` and `$1`? And I assume you are wrapping them in `(...)` to make them expressions, because maybe the interpreter, would spit back an error if you didn't? – Antonio Pavicevac-Ortiz Apr 16 '16 at 15:31
  • The second replace `.replace(/[_\s]+(?=[a-zA-Z])/g, '-')` is first checking for a `_` and a `whitespace` character, then it seems you are saying lets concatenate `(?=[a-zA-Z])/g, '-')` what does all that mean. Thanks in advance! – Antonio Pavicevac-Ortiz Apr 16 '16 at 15:34
  • hey, there are a few main steps and you have the majority correct, I would recommend you use this website to break down and understand the above yourself: https://regex101.com/. If you paste in the two I use (without the / /) you can get a really nice printout of the what they do! good luck – omarjmh Apr 16 '16 at 15:53
4

Here's my solution, simple with regex and works for all cases

function spinalCase(str) {
  return str.replace(/([A-Z])/g,' $1') /*Find all cap and add space at the start*/
        .replace(/[^A-Za-z0-9]/g,' ') /*Find all non alpha numeric and replace it with space*/
        .replace(/\s{1,}/g,"-") /*Convert all spaces to -*/
        .replace(/^\-|[\-]$/g,'') /*Slice - at the start and end*/
        .toLowerCase(); /*LowerCase it*/
}
prajnavantha
  • 1,111
  • 13
  • 17
3
function spinalCase(str) {
//Split the string at one of the following conditions 
        //a whitespace character [\s] is encountered
        //underscore character [_] is encountered
        //or by an uppercase letter [(?=[A-Z])]
//Join the array using a hyphen (-)
//Lowercase the whole resulting string 

   return str.split(/\s|_|(?=[A-Z])/).join('-').toLowerCase(); 

}
1

here's my solution, a bit less heavy on the regex:

function spinalCase(str) {
  var newStr = str[0];

  for (var j = 1; j < str.length; j++) {
    // if not a letter make a dash
    if (str[j].search(/\W/) !== -1 || str[j] === "_") {
      newStr += "-";
    }
    // if a Capital letter is found 
    else if (str[j] === str[j].toUpperCase()) {
      // and preceded by a letter or '_'
      if (str[j-1].search(/\w/) !== -1 && str[j-1] !== "_") {
        // insert '-' and carry on
        newStr += "-";
        newStr += str[j];
      }
      else {
        newStr += str[j];
      }
    }
    else {
        newStr += str[j];
    }
  }

  newStr = newStr.toLowerCase();
  return newStr;
}
Yup.
  • 1,883
  • 21
  • 18
1
function spinalCase(str) {

  // any string followed by upperCase letter
  var  re = /(?=[A-Z])/g;  

  // any string followed by space and upperCase/lowerCase letter 
  var  re2=/(?=\s[A-Z]|\s[a-z])/g;

  // any string of 2 or more '-'
  var re3 = new RegExp("-{2,}", "g");

  var space = new RegExp(" ","g");
  var hyphen = new RegExp("_","g");

  str = str.replace(hyphen,"-");
  str = str.replace(re, '-');   
  str = str.replace(re2,"-");
  str = str.replace(re3,"-"); 
  str = str.replace(space,"");
  str = str.toLowerCase();
  if(str.slice(0,1)== '-'){
    str = str.replace("-","");  
  }     
  return str;
}

spinalCase('This Is Spinal Tap');
sonali
  • 762
  • 10
  • 23
1
function spinalCase(str) {
  var newStr = '';
  var arr = str.split('');
  for (var i = 0; i < arr.length; i += 1) {
    if (i > 0) {
      if (arr[i] >= 'A' && arr[i] <= 'Z') {
        if (arr[i - 1] >= 'a' && arr[i - 1] <= 'z') {
          newStr += '-';
          newStr += arr[i].toLowerCase();
          continue;
        }
      }
      else if (arr[i] === ' ' || arr[i] === '_') {
        newStr += '-';
        continue;
      }
    }
    newStr += arr[i].toLowerCase();
  }
  return newStr;
}

spinalCase("AllThe-small Things");
1

I was stuck on this too, but found a simpler solution:

function spinalCase(str) {
  const regex =new RegExp(/(([A-Z]|[a-z])[a-z]+)/,'g');
  str=str.match(regex);
  return str.join('-').toLowerCase();
}

console.log(spinalCase('AllThe-small things'));
Mahdi Abdi
  • 682
  • 6
  • 27
M3rlin
  • 53
  • 1
  • 8
1

A beginner friendly solution:

function spinalCase(str) {
//change camelCase to title case(i.e. change 'markIsHere' to 'Mark Is Here') 
    let newStr = str.replace(/([a-z])([A-Z])/g, ('$1 $2'));
//replace space with '-'
    newStr = newStr.replace(/ /g, '-');
//replace underscores with '-'
    newStr = newStr.replace(/_/g,'-');
//change the result to lowercase
    return newStr.toLowerCase()
}
  • Please don't post only code as an answer, but also provide an explanation of what your code does and how it solves the problem of the question. Answers with an explanation are usually more helpful and of better quality, and are more likely to attract upvotes – Ran Marciano Feb 09 '21 at 07:59
0
function spinalCase(str) {

  // Create a variable for the white space and underscores
  var regex = /\s+|_+/g;

  // Replace low-upper case to low-space-uppercase
  str = str.replace(/([a-z])([A-Z])/g, '$1 $2');

  // Replace space and underscore with dashes
  return str.replace(regex, '-').toLowerCase();

}
0
function insert(arr){
    arr = arr.split("");
    for(let i in arr){
      if (/[A-Z]/.test(arr[i])&& i>0){
        arr[i] = "-" + arr[i];
      }
    }
    arr = arr.join("");
    return arr;
  }

function spinalCase(str) {
  
  str = str.split(/\s+|_/);
  str = str.map(item=>insert(item));
  str = str.join("-");
  str = str.toLowerCase();
  return str;
  
}
0

I've come up with the following. For the FCCamp purpose it works

function spinalCase(str) {
  return str
    .split(/(?=[A-Z])/)
    .join()
    .split(/[_\W+]/)
    .join(' ')
    .split(/\s+/)
    .join('-')
    .toLowerCase()
}
spinalCase("AllThe-small Things");
Danny Lenko
  • 45
  • 1
  • 8
0

I have no illusions that anybody is going to care now ;), but I would have searched for positions in-between words, as indicated by capital letters, and placed hyphens there instead. For example:

const spinalCase = (str) => {
    let regex = /(?:\B|[ _])(?=[A-Z])/g;
    return str.replace(regex, '-').toLowerCase();
}

console.log(spinalCase('AllThe-small Things'));
oriberu
  • 1,186
  • 9
  • 6