정규식
🔑 키워드
정규식, 정규식을 자주 사용하는 메서드(match, replace, exac, test...)
❓ 정규식 사용하기
정규식은 한번 알아 놓으면 굉장히 유용하다.
정규식 사용법을 예제를 통해 알아보자
정규표현식
Anchors
beginning ^
문자열의 시작 혹은 여러 줄에서 멀티라인 플래그(m)을 사용할 때 라인의 시작 부분과 매칭한다.
즉 문자가 아니라 위치를 찾아야 할 때 사용한다.
문자열에서 맨 앞에 있는 문자(1개 이상)를 찾을 때
^\w+
she sells seashells
end $
문자열의 끝, 혹은 멀티라인 플래그(m)을 사용할 때 라인의 끝을 매칭한다.
해당 문자 또한 문자가 아니라 위치를 찾아야할 때 사용한다.
문자열에서 맨 뒤에 있는 문자를 찾을 때
\w$
she sells seashells
word boundary \b
and not word boundary \B
\b
: 문자열 내에서 문자 바운더리와 매칭한다.\B
: 반대로 바운더리가 아닌 부분과 매칭한다.
문자열에서 문자 처음에만 대문자로 만드는 작업을 할 때 첫문자을 찾기 위해서
/\b\w/g
she sells seashells
Quantifiers & Alternation
plus +
앞의 토큰이 1개 혹은 그 이상일 때 매칭
문자열에서 b문자가 앞에 오고, 이후 문자가 1개 이상인 경우를 찾을 때
/b\w+/g
b be beeerrrr
- 위에 식에서는
+
를 사용하였으므로 1개 이상의 문자열이 뒤에 와야하기 때문에b
는 정규식에 매칭되지 않는다
star *
앞 토큰이 0개 혹은 그 이상일 때 매칭
문자열에서 b문자가 앞에오고, 이후 문자가 0개 이상인 경우를 찾을 때
/b\w*/g
b be beeerrrr
- 이때는
*
을 사용하기 때문에\w
에 해당하는 값이 0개이더라도 매칭되기에b
또한 정규식과 매칭된다.
문자열에서 특정 문자열이 0개 이상인 경우를 찾을 때
/(ab)+/g
abababab abbbbb
- () 를 사용하여 캡처된 문자열을 사용할 수 있다.
quantifier {n, m}
매칭되는 문자가 n 개 이상 m 개 이하일 때 매칭된다.
\w{2,} - 문자 2개 이상
\w(2, 4} - 문자 2개 이상 4개 이하
a(bc){2, 4} - a와 2개 이상 5개 이하의 bc
optional ?
앞 토큰과 매칭되는 문자열이 0개 혹은 1개
/colou?r/g
color colour
lazy ?
위에서 사용되는 ?와 달리 해당 물음표는 앞에 다른 수를 세는 표현과 함께 오며 기존 탐욕적으로 모든 문자를 다 찾는 방식과 다르게 레이지하게 문자를 찾는다.
// 탐욕적으로 태그 토큰을 찾을 때
/\<.+\>/
<div> hi div tag</div>
// 레이지하게 태그 토큰을 찾는다면
/\<.+?\>/g
<div> hi div tag</div>
alternation - | []
OR 연산자로 | 앞 혹은 뒤 토큰과 매칭되는 값을 찾는다.
혹은 [] 로 사용할 수 있다.
a(b|c)
a[bc]
Character classes
character set []
OR 연산자와 마찬가지로 [ABC] 라고 한다면 A혹은 B혹은 C를 의미한다.
/[aeiou]/g
glib vex
negated set [^]
캐릭터 셋과 반대로 하당 셋에 포함된 문자열이 아닌 모든 문자를 의미한다.
/[^aeiou]/g
apple
range [-]
[a-z] - a 부터 z 까지
[A-Z] - a 부터 Z 까지
[0-9] - 0 부터 9 까지
dot .
라인브레이크(\n
, \r
) 를 제외한 모든 문
word & not word \w
\W
문자, 숫자, 언더바를 포함하는 모든 문자와 매칭
그반대의미의 \W
대문자를 사용하면 반대의 의미를 가짐
digit & not digit \d
\D
whitespace & not whitespcae \s
\S
스페이스, 탭, 줄바꿈과 매칭
Groups & References
capturing group ()
괄호 내에 있는 문자열은 해당 문자열에 매칭되는 부분 문자(열)을 기억해둘 수 있고, 이렇게 캡쳐된 문자를 정규식에서 재사용하거나 문자열 메서드에서 콜백함수 혹은 특수 교체 패턴으로 사용할 수 있다.
// 콜백 함수로 사용하는 경우
`javascript`.replace(/(java)(script)/, (match, p1, p2) => `${match}: ${p2}-${p1}`)
// javascript: script-java
특수 교체 패턴
String.prototype.replace() - JavaScript | MDN
// 특수 교체 패턴을 사용할 경우
`javascript`.replace(/(java)(script)/, `$2-$1`)
// script-java
"javascript".replace(/(java)script/, '$&')
// javascript
non-capturing group (?:)
여러 토큰들을 그룹화하여 사용하지만 캡처링하지는 않을 때 사용한다.
/(?:ha)+/g
hahaha haa hah!
위와 같이 그룹화는 되지만,
"hahaha haa hah!".match(/(?:ha)+/)
0 : "hahaha"
groups : undefined
index : 0
input : "hahaha haa hah!"
length : 1
캡처링은 되지 않는다.
그냥 그룹핑과 비교해보면 더 쉽게 알 수 있다.
"hahaha haa hah!".match(/(ha)+/)
0: "hahaha"
1: "ha"
groups: undefined
index: 0
input: "hahaha haa hah!"
length: 2
Lookahead (?=)
이 또한 그룹 패턴으로 해당 그룹 내에 있는 패턴에 뒤에 올 때만 매칭된다.
더하여 해당 그룹내에 있는 패턴은 매칭 결과에 포함되지 않는다.
/\d+(?=px)/g
1pt 2px 3em 4px
negative lookahead (?!)
이 또한 그룹 패턴으로 해당 그룹 내에 있는 패턴이 뒤에 오지 않을 때만 매칭된다.
더하여 해당 그룹내에 있는 패턴은 매칭 결과에 포함되지 않는다.
/\d+(?!px)/g
1pt 2px 3em 4px
Lookbehind (?<=)
이 또한 그룹 패턴으로 해당 그룹 내에 있는 패턴이 앞에 올 때만 매칭된다.
더하여 해당 그룹내에 있는 패턴은 매칭 결과에 포함되지 않는다.
/(?<=\d)px/g
1px fourpx
negative lookbehind (?<!)
이 또한 그룹 패턴으로 해당 그룹 내에 있는 패턴이 앞에 오지 않을 때만 매칭된다.
더하여 해당 그룹내에 있는 패턴은 매칭 결과에 포함되지 않는다.
/(?<!\d)px/g
1px fourpx 10px
Flags
- g(global): 매칭되는 모든 항목을 찾는다 (기존에는 매칭되는 한개의 항목을 찾으면 끝남)
/d+(?=px)/g
1pt 2px 3em 4px
/d+(?=px)/
1pt 2px 3em 4px
- m(multi-line) anchor(^ 또는 $)가 문자열 전체가 아닌, 줄 각각에 매칭하여 줄별로 정규식 패턴을 매칭시킬 수 있습니다
/^[A-Z]/m
hello
Hello
/^[A-Z]/
hello
Hello
- i(insensitive) 대소문자 구분을 무시하고 매칭합니다
/abc/i
ABC
실습 예제
예제를 통해 정규식을 실제로 사용해보자
https://school.programmers.co.kr/learn/courses/30/lessons/12951
프로그래머스 문제 중에 JadenCase 문자열 만들기 이다.
모든 문자열 중에서 첫 번째 문자가 대문자이고 나머지 문자는 소문자인 문자열을 만드는 문제이다.
예를 들어
input: "3people unFollowed me",
output: "3people Unfollowed Me"
input: "for the last week"
output: "For The Last Week"
우선 문자열에서 1️⃣띄어쓰기로 구분되는 문자열 중 맨 앞자리 문자를 찾아서 2️⃣소문자라면 대문자로 만들어주면 된다.
1️⃣ 정규식으로 문자열 중 맨 앞자리 문자를 찾는다
띄어쓰기로 매칭되는 문자(맨처음 문자 포함) = word bounday \b
"for the last week"
각 문자에 해당하는 정규식은 두가지 형태로 모두 찾을 수 있다.
1) 띄어쓰기로 매칭되는 문자와 맨처음 문자 모두 찾기
/((?<=\s)([a-z])|^([a-z]))/g
// positive lookbehind (?<= ): 앞에 위치한 토큰(띄어쓰기)과 일치하하나 그룹에 포함시키지는 않음
// OR oper ( | )
// anchor start ^
// capturing(grouping) ()
for the last week
2) 문자 바운더리 다음에 위치한 문자 모두 찾기
/\b([a-z])/g
// word boundary \b
// capturing(grouping) ()
for the last week
2️⃣ 이렇게 찾은 문자들을 대문자로 만들어주기
참고: replace 메서드 매개변수를 함수로 사용하기
- 두번째 매개변수로 함수를 지정할 수 있다
- 함수는 정규표현식 매치가 수행된 후 호출된다
- 함수의 반환값은 교체될 문자열이 된다.. (참고: 윗쪽에서 언급된 특수 교체 패턴은 반환값에 적용되지 x)
- 만약 정규표현식의 플래그로 글로벌(g)이 오는 경우, 함수는 매치될 때마다 계속 호출
결과
str.toLowerCase().replace(/\b([a-z])/g, (match) => match.toUpperCase())
match에 해당하는 값이 각각 f, t, l, w 이고, 해당값을 반환값(교체될 문자)으로 해당 값의 toUpperCase()로 대문자로 변환하여 반환
-> 'For The Last Week'
이와 같이 정규식을 통해 문제를 해결할 수 있다
🔖참고자료
https://regex101.com/r/cO8lqs/16
https://chrisjune-13837.medium.com/정규식-튜토리얼-예제를-통한-cheatsheet-번역-61c3099cdca8
https://blog.rhostem.com/posts/2018-11-11-regex-capture-group
https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/String/replace