Spinal Tap Case
문제
문자열을 spinal case로 변환하라. Spinal case란 소문자로 이루어지고 dash(-)로 연결된 문자열을 말한다.
예시
spinalCase("This Is Spinal Tap") should return "this-is-spinal-tap". Passed spinalCase("thisIsSpinalTap") should return "this-is-spinal-tap". Passed spinalCase("The_Andy_Griffith_Show") should return "the-andy-griffith-show". Passed spinalCase("Teletubbies say Eh-oh") should return "teletubbies-say-eh-oh". Passed spinalCase("AllThe-small Things") should return "all-the-small-things".
내가 푼 답
function spinalCase(str) { var newStr = str.split(/\W|_/).join("-"); function replacer(match, p1, p2) { return [p1, p2].join('-'); } if(newStr.match(/(?<=[a-z])[A-Z](?=[a-z])/)) { newStr = newStr.replace(/([a-z]+)([A-Z]+)(?=[a-z]+)/g, replacer).split(/\W/).join('-'); } return newStr.toLowerCase(); }
replace 메소드를 쓸 때에 매개변수로 함수를 쓸 수 있다는 것을 구글링하다가 처음 알았다. mdn문서의 replace를 참조하여 replacer 함수를 만들었다.
그리고 정규식에 lookahead(?=)는 알고 있었는데, 매치하고자 하는 문자열 전에 특정 문자가 있는지 찾을 수 없을까 구글링하다가 lookbehind 기능(?<=)이 ES2018에 새로 추가되었다는 것을 알았다.
Basic Solution
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 - return str.replace(regex, '-').toLowerCase(); }
나도 소문자 뒤에 있는 대문자를 발견하고 그 앞을 구분해야 한다는 것을 알았다. 이 솔루션은 replace를 쓸 때 매개변수로 함수를 쓰지 않고
'$1 $2'
로 간단하게 그 사이에 띄어쓰기를 넣었다.'$1'
은 첫 번째 캡처링 그룹을 의미하고'$1'
과'$2'
사이를 띄어써야 소문자와 대문자 사이에 띄어쓰기가 되는 것을 의미한다.
Intermediate Solution
function spinalCase(str) { // Replace low-upper case to low-space-uppercase str = str.replace(/([a-z])([A-Z])/g, '$1 $2'); // Split on whitespace and underscores and join with dash return str.toLowerCase().split(/(?:_| )+/) .join('-'); }
?:
는 비포획그룹을 의미한다. (mdn 참조) 예를 들어/foo{1,2}/
에서는 o만 해당되지만/(?:foo){1,2}/
는 foo전체에 해당된다.
Advanced Solution
function spinalCase(str) { return str.split(/\s|_|(?=[A-Z])/).join('-').toLowerCase(); }
lookahead로 한 번에 쪼갤 수도 있다.