호다닥

Javascript: 초보자를 위한 정규식(Regular Expressions) 배우기 본문

Javascript

Javascript: 초보자를 위한 정규식(Regular Expressions) 배우기

3jun 2018. 8. 7. 16:24

JavaScript: Learn Regular Expressions for Beginners

출처 : codeburst.io, Brandon Morelli

해당 내용은 Brandon Morelli의 article을 개인적으로 번역한 내용이며, 잘못 번역된 부분이 있을 수 있습니다. 원문은 위에 적힌 주소에서 확인하실 수 있습니다.

 

 

 

자바스크립트에서 정규표현식은 문자열에서 문자조합과 대응시키기 위해 사용되는 객체이다. 

 

 

첫번째 정규표현식 만들기

정규표현식을 만드는 방법에는 2가지가 있다. 

하나는 정규표현식 리터럴 방식이고 하나는 정규표현식 생성자 함수를 사용하는 것이다. 

// Regular Expression Literal - Uses slashes ( / ) to enclose
var option1 = /cat/;
// Regular Expression Constructor
var option2 = new RegExp("cat");

 

일반적으로 추후에 정규표현식을 수정하지 않는다면 regex literal 방식을 사용하는 것이 좋고, 정규표현식을 추후에 수정하려고 하거나, 다른 변수와 함께 사용하려면 생성자 method를 사용하는 것이 낫다. 

 

RegExp.prototype.test()

위에서 이미 정규표현식이 객체라고 언급을 했다. 이것은 우리가 사용할 수 있는 method들이 존재함을 뜻한다. 

가장 기본적인 method는 test이다. 이것은 Boolean을 return한다. 

 

True : 문자열이 regex 패턴에 포함된다.

False : 일치하는 부분이 없다. 

console.log(/cat/.test(“the cat says meow”));
// true
console.log(/cat/.test(“the dog says bark”));
// false

 

 

 

기본적인 Regex들

정규표현식은 이해하는데 가장 좋은 방법은 일반적인 명령어들과 기호들을 기억하는 것이다. 

Symbols

.    임의의 글자 한개를 의미한다. line break는 제외한다.

*    앞의 표현이 0개 이상이다. 

+    앞의 표현이 1개 이상이다.

?    앞에 온 표현이 선택적이다.( 있을수도 없을수도 있다. )

^    시작하는 글자와 일치한다.

$    마지막 글자와 일치한다.

 

Character groups

\d    숫자와 같다.

\w    모든 문자와 같다. (밑줄문자를 포함한 알파벳로마자)
[XYZ]    문자셋으로 괄호안의 어떤 문자와도 대응된다. [A-Z]처럼 범위를 지정해줄 수도 있다.
[XYZ]+    세트안에 있는 하나 혹은 그 이상의 어떤 글자와도 대응된다.
[^A-Z]    하나의 문자세트 안에서 ^는 부정의 의미이다. 여기서는 어떤 대문자와도 대응되지 않는다. 
 

Flag

다섯개의 선택가능한 flag들이 있다. 그것들은 개별적으로 사용될수도 함께 사용될 수도 있고 closing slash 뒤에 위치할 수도 있다. 
 
예시 : / [A-Z] / g 
g ― Global search
i  case insensitive search
 

Advanced

(x)  Capturing Parenthesis (포획괄호), x에 대응되고 기억되어 나중에 사용될 수 있게 한다. 
(?:x)  Non-capturing Parenthesis (비포획 괄호), x에 대응하지만 기억하지는 않는다.
x(?=y)  Lookahead, y가 뒤따라오는 x에만 대응된다.
 

 

 

 

Test()-ing our Learning

어떤 숫자를 위한 문자열을 테스트해보자. 우리는 \d 를 사용하여 이것을 실행할 수 있다. 
console.log(/\d/.test('12-34'));
// true
String 안에 적어도 하나의 숫자가 있다면 위 코드의 return 값은 true이다. 
만약 우리가 형식에 맞추고자 한다면 어떨까? 우리는 \d를 중복해서 사용하여 형식을 정할 수 있다. 
console.log(/\d\d-\d\d/.test('12-34'));
// true
console.log(/\d\d-\d\d/.test('1234'));
// false
만약 '-'의 앞이나 뒤에 숫자들이 몇개나 오던지 상관없다면 어떨까? (단, 적어도 하나는 있어야한다.) 우리는 +를 사용하여 \d를 한개의 숫자 혹은 그 이상과 대응할 수 있다. 
console.log(/\d+-\d+/.test('12-34'));
// true
console.log(/\d+-\d+/.test('1-234'));
// true
console.log(/\d+-\d+/.test('-34'));
// false
좀 더 단순하게는 괄호를 사용하여 그룹화를 할 수 도 있다. 
console.log(/me+(ow)+w/.test('meeeeowowoww'));
// true

위 코드가 어떻게 동작되었는지 좀 더 자세히 살펴보면 아래와 같다.

/me+(ow)+w/
m     => matching a single letter 'm'
e+    => matching the letter 'e' one or more times
(ow)+ => matching the letters 'ow' one or more times
w     => matching the letter 'w' once
'm' + 'eeee' +'owowow' + 'w'

여기서 볼 수 있듯이 괄호 바로 뒤에 +와 같은 연산자들을 사용할 수 있다. 그것들은 괄호 안의 요소 전체에 영향을 준다.

 

다음으로 넘어가기에 앞서 ? 연산자도 한번 살펴 보자. 이것은 이전의 글자를 선택적으로 만든다. 아래 예제코드에서 볼 수 있듯이 두 test case에서 's'는 선택적인 요소로 간주되었기 때문에 모두 true를 return한다. 

console.log(/cats? says?/i.test('the Cat says meow'));
// true
console.log(/cats? says?/i.test('the Cats say meow'));
// true

또한 /i flag도 추가해주었기 때문에 'cats'와 'Cats'가 대응될 수 있게 되었다. 

 

 

 

 

Considerations & Tips

정규표현식은 /로 감싸져있기 때문에 slash를 찾고자 한다면 backslash를 사용해야한다. 또한 ?와 같이 특별한 의미를 가진 기호들도 마찬가지 이다. 

var slashSearch = /\//;
var questionSearch = /\?/;

\d 는 [0-9]와 같다. : 각각 숫자와 대응한다.

\w 는 [A-Za-z0-9_]와 같다. : 각각 알파벳,로마자와 밑줄에 대응하낟.

 

 

 

Project: CamelCase에 띄어쓰기 추가하기

이 예시에서는 camelCase에 대해 좀 더 이해하고 단어 사이에 띄어쓰기를 추가하는 방법을 배울 것이다. 

removeCc('camelCase') // => should return 'camel Case'

정규표현식을 사용하면 매우 간단하게 해결할 수 있다. 우선 우리는 모든 대문자를 찾아야한다. 

우리는 문자셋 찾기와 전역적인 변환을 통해 손쉽게 이것을 실행할 수 있다. 

This will match the C in 'camelCase'
/[A-Z]/g

그럼 이제 C앞에 어떻게 띄어쓰기를 추가할 수 있을까?

우리는 Capturing Parenthesis를 사용해야한다. Capturing Parenthesis는 값에 대응하고 이것을 기억할 수 있게 하여 나중에 이것을 사용할 수 있게 해준다. 

Use capturing parenthesis to remember our matched capital letter
/([A-Z])/
Access the captured value later with
$1

위에서 captured value에 접근하기 위해 $1을 사용한 것을 확인할 수 있다. 만약 우리가 두개의 capturing parenthesis를 가지고 있다면 우리는 capture value를 참조하기 위해 $1과 $2를 사용해야한다. 즉, capturing parenthesis 만큼 사용해야한다.

 

만약 괄호를 사용해야하지만 value를 capture하지 않으려면 반드시 non-capturing parenthesis를 사용해야한다. : (?:x) , 이것은 즉 x와 대응되지만 기억하지 않는다는 것이다. 

 

다시 본론으로 돌아가서 우리는 capturing parenthesis를 어떻게 실행할 수 있을까? .replace() 문자열 method를 사용한다. 두번째로 언급했듯이 $1을 추가하고 여기에 따옴표를 사용하는 것이 중요하다.

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

위 코드가 정상적으로 동작할가? 아래 코드를 다시 한번 보도록 하자. 우리는 대문자를 capturing 한 다음 이것을 단순히 capture된 동일한 문자로 바꿔주었다. 아직 띄어쓰기를 추가해줄 필요가 있다. 따옴표 안에 $1 변수 바로 앞에 띄어쓰기를 삽입하면 결과값은 모든 대문자 앞에 띄어쓰기를 추가하여 나타날 것이다. 

function removeCc(str){
  return str.replace(/([A-Z])/g, ' $1');  
}
removeCc('camelCase') // 'camel Case'
removeCc('helloWorldItIsMe') // 'hello World It Is Me

 

 

 

 

Project: Remove Capital Letters 대문자 지우기

이것 또한 띄어쓰기를 추가하는 것과 매우 비슷하지만 조금 더 복잡하다. 

 

먼저, 우리는 모든 대문자들을 선택해야한다. 이것은 위 project와 유사하다. global modifier로 문자셋을 찾는다.

/[A-Z]/g

그리고 replace method를 또 사용할 것이다. 그러나 이번에는 어떻게 문자를 소문자로 만들까?

function lowerCase(str){
  return str.replace(/[A-Z]/g, ???);  
}

힌트 : replace()를 사용하여 두번째 parameter로 함수를 명시할 수 있다. 

 

우리는 대응된 값을 소문자로 바꾸기 위해 화살표 함수를 이용할 것이다. 

함수에 replace()를 사용할 경우 함수는 대응이 된 후에 실행될 것이다. 그리고 함수의 결과는 string 을 바꾸는데 사용될 것이다. 만약 대응이 전체에서 다중으로 이뤄진다면 함수는 각 대응이 이뤄진 후에 호출될 것이다.

function lowerCase(str){
  return str.replace(/[A-Z]/g, (u) => u.toLowerCase());
}
lowerCase('camel Case') // 'camel case'
lowerCase('hello World It Is Me') // 'hello world it is me'

 

 

 

 

Project: 첫번째 글자 대문자로 바꾸기

본문을 읽기전 아래 예제 코드정보를 보고 직접 해결해보자.

capitalize('camel case') // => should return 'Camel case'

 

우리는 replace () method에 다시한번 화살표 함수를 사용할 것이다. 그러나 이번에 우리는 string에서 첫번째 글자만을 찾을 것이다. 첫번째 글자를 기억하기 위해 ^를 사용한다.

 

^에 대해 좀더 깊이있게 살펴보도록 하자. 먼저 아래 예제를 recall 하자.

console.log(/cat/.test('the cat says meow'));
// true

우리가 함수에 ^를 추가하면 더이상 true가 return되지 않는다. cat은 string이 시작되는 글자가 아니기 때문이다.

console.log(/^cat/.test('the cat says meow'));
// false

우리는 ^가 string이 시작되는 첫번째 소문자에 대응하길 원한다. 때문에 우리는 [a-z]를 우리의 문자셋 바로 앞에 추가한다.

이것은 첫번째 글자가 소문자일 때만 target으로 잡을 것이다.

/^[a-z]/

우리는 오직 하나의 대응만을 원하기 때문에 더이상 global modifier를 사용하지 않는다. 

이제 우리는 정규표현식을 replace method 내부로 연결할 수 있고 화살표 함수의 두번째 argument로 추가할 수 있다. 

function capitalize(str){
  return str.replace(/^[a-z]/, (u) => u.toUpperCase());
}
capitalize('camel case') // 'Camel case'
capitalize('hello world it is me') // 'Hello world it is me'

 

 

 

 

Project: 계속해서 배우기

  1. 이전의 3가지 함수들을 하나의 함수 안에 통합하고, 그 함수로 하여금 camelCase string을 정규표현식으로 변환시키게 할 수 있나?
  2. string의 끝에 .(period)를 추가할 수 있나?
  3. 모든것을 뒤집어라. stiring을 camelCase Hashtag로 변화시킬 수 있나?

 

Comments