알고리즘 기초 문제들을 풀면서 정규표현식 관련된 문제에서 어려움을 느끼고, 해결법에 잘 접근하지 못한다는 것을 알았습니다. 그래서 관련 문제를 풀면서 정규표현식을 익히고자 합니다 :)
정규 표현식이란?
문자열에서 특정 문자 조합을 찾기 위한 패턴
- 정규 표현식은 문자열 대상으로 패턴 매칭 기능을 제공한다.
정규 표현식의 생성
1. 정규 표현식 리터럴
정규식 구성 코드는 패턴과 플래그로 구성된다.
1
2
3
4
| const target = "Is this all there is?";
// 패턴 : is, 플래그 : i => 대소문자 구별 X
const regexp = /is/i;
regexp.text(target); // true;
|
2. RegExp 생성자 함수
- pattern : 정규 표현식의 패턴
- flags : 정규 표현식의 플래그 (g, i, m, u, y)
1
| new RegExp(pattern[, flags]);
|
1
2
3
4
| const target = "Is this all there is?";
// 패턴 : is, 플래그 : i => 대소문자 구별 X
const regexp = new RegExp(/is/i);
regexp.text(target); // true;
|
변수를 사용해 동적으로 RegExp 객체를 생성할 수 있다.
1
2
3
| const count = (str, chr) => (str.match(new RegExp(char, 'gi')) ?? []).length;
count("Is this all there is?", 'is'); // -> 3
count("Is this all there is?", 'xx'); // -> 0
|
정규식 메서드
메서드 | 의미 |
---|
("문자열").match(/정규표현식/플래그) | “문자열”에서 “정규표현식”에 매칭되는 항목들을 배열로 반환 |
("문자열").replace(/정규표현식/, "대체문자열") | “정규표현식”에 매칭되는 항목을 “대체문자열”로 변환 |
("문자열").split(정규표현식) | “문자열”을 “정규표현식”에 매칭되는 항목으로 쪼개어 배열로 반환 |
("문자열").search(정규표현식) | |
(정규표현식).test("문자열") | “문자열”이 “정규표현식”과 매칭되면 true , 아니면 false 반환 |
(정규표현식).exec("문자열") | “정규표현식”에 매칭되는 항목들을 배열로 반환 (단, 무조건 첫 번째 매칭 결과만 반환) |
RegExp.prototype.exec
1
2
3
4
5
6
7
8
9
| // 정규표현식을 담은 변수
const regex = /apple/; // apple 이라는 단어가 있는지 필터링
const txt = "Hello banana and apple hahahaha";
txt.match(regex); // ['apple']
txt.replace(regex, "watermelon"); // 'Hello banana and watermelon hahahaha'
regex.test(txt); // true
regex.exec(txt); // ['apple', index: 4, input : "Hello banana and apple hahahaha"]
|
** g플래그를 지정해도 첫번째 결과만 반환 **
📌 정규식 플래그
정규식 플래그는 정규식을 생성할 때 검색 방식을 설정하기 위해 사용한다.
Flag | Meaning | Desc |
---|
i ⭐️⭐️⭐️ | Ignore Case | 대소문자를 구별하지 않고 검색 |
g ⭐️⭐️⭐️ | Global | 패턴과 일치하는 모든 문자열을 전역 검색 |
m ⭐️⭐️⭐️ | Multi Line | 문자열의 행이 바뀌더라도 검색을 계속한다. |
s | | .(모든 문자 정규식)이 개행 문자 \n도 포함하도록 |
u | unicode | 유니코드 전체를 지원 |
y | sticky | 문자 내 특정 위치에서 검색을 진행하는 ‘sticky’ 모드를 활성화 |
1
2
3
4
5
6
| const target = "Is this all there is?";
target.match(/is/); // ['is', index: 5, input: 'Is this all there is?', groups: undefined]
target.match(/is/i); // ['Is', index: 0, input: 'Is this all there is?', groups: undefined]
target.match(/is/g); // ['is', 'is']
target.match(/is/ig); // ['Is', 'is', 'is']
|
📌 정규식 패턴
1
2
| 리터럴 문자 (정규 문자) : 일반 문자, \0, \n, \t, \v, \f, \r, \xhh, \uhhhh, \cX
메타 문자 (정규 표현식의 구문 문자) : ^ $ \ . * + ? ( ) [ ] { } |_
|
✅ 기본 문자
기호 | 설명 | 예제 | 매칭 결과 |
---|
a-zA-Z | 영어알파벳(-으로 범위 지정) | | |
ㄱ-ㅎ가-힣 | 한글 문자(-으로 범위 지정) | | |
0-9 | 숫자(-으로 범위 지정) | | |
. | 임의의 문자 한 개 | /a.b/ | "acb" , "a8b" (✔), "ab" , "abb" (❌) |
\d | 숫자 ([0-9] 와 동일) | /\d+/ | "abc123" → "123" |
\D | 숫자가 아닌 문자 ([^0-9] 와 동일) | /\D+/ | "abc123" → "abc" |
\w | 단어 문자 ([a-zA-Z0-9_] ) | /\w+/ | "hello_123!" → "hello_123" |
\W | 단어 문자가 아닌 문자 ([^a-zA-Z0-9_] ) | /\W+/ | "hello_123!" → "!" |
\s | 공백 (\t , \n , \r 포함) | /\s+/ | "hello world" → " " |
\S | 공백이 아닌 문자 | /\S+/ | "hello world" → "hello" |
✅ 반복 패턴
기호 | 설명 | 예제 | 매칭 결과 |
---|
* | 0개 이상 반복 ({0,} ) | /go*d/ | "gd" , "god" , "good" , "goood" (✔) |
+ | 1개 이상 반복 ({1,} ) | /go+d/ | "god" , "good" , "goood" (✔), "gd" (❌) |
? | 0개 또는 1개 ({0,1} ) | /go?d/ | "gd" , "god" (✔), "good" (❌) |
{n} | 정확히 n개 반복 | /a{3}/ | "aaa" (✔), "aa" (❌) |
{n,} | 최소 n개 반복 | /a{2,}/ | "aa" , "aaa" , "aaaa" (✔) |
{n,m} | n개 이상, m개 이하 반복 | /a{2,4}/ | "aa" , "aaa" , "aaaa" (✔), "a" , "aaaaa" (❌) |
✅ 검색 패턴
기호 | 설명 | 예제 | 매칭 결과 |
---|
| | OR | /apple|banana/ | "I like apple" (✔), "I like banana" (✔) |
[] | 문자 클래스 (괄호 안의 문자 중 하나) | /[aeiou]/ | "apple" → "a" (✔) |
[^문자] | 부정 문자 클래스 (괄호 안의 문자 제외) | /[^0-9]/ | "hello123" → "h" (✔) |
^ | 문자열의 시작 | /^hello/ | "hello world" (✔), "world hello" (❌) |
$ | 문자열의 끝 | /world$/ | "hello world" (✔), "world hello" (❌) |
\b | 그룹 검색(분류X) | /\bcat\b/ | "cat is here" (✔), "caterpillar" (❌) |
\B | 단어의 처음/끝이 아님 | /\Bcat\B/ | "caterpillar" (✔), "cat " (❌) |
\n | 그룹 참조 (n번째 그룹) | /(\d+)-\1/ | "123-123" (✔), "123-456" (❌) |
✅ 그룹 패턴 (꽤 난이도가 있는 표현식)
기호 | 설명 | 예제 | 매칭 결과 |
---|
() | 그룹 검색 및 분류(match메서드에서 그룹별로 묶어줌) | /(go)+d/ | "gogod" , "gogogod" (✔) |
(? : 패턴) | 캡처하지 않는 그룹 | /(?:go)+d/ | 그룹 참조 없이 "gogod" (✔) |
(?=...) | 긍정형 전방 탐색 (앞에 특정 패턴이 있는지 확인) | /\d(?=px)/ | "10px" → "0" (✔) |
(?!...) | 부정형 전방 탐색 (앞에 특정 패턴이 없는지 확인) | /\d(?!px)/ | "10px" → "1" (✔) |
(?<=...) | 긍정형 후방 탐색 (뒤에 특정 패턴이 있는지 확인) | /(?<=\$)\d+/ | "$100" → "100" (✔) |
(?<!...) | 부정형 후방 탐색 (뒤에 특정 패턴이 없는지 확인) | /(?<!\$)\d+/ | "100" → "100" (✔), "$100" (❌) |
6. 특수 기호 & 플래그
기호 | 설명 | 예제 | 매칭 결과 |
---|
\ | 이스케이프 문자 | /\./ | "hello.world" → "." (✔) |
g | 글로벌 검색 (전체 검색) | /is/g | "this is" → ["is", "is"] |
i | 대소문자 구분 없음 | /hello/i | "HELLO" (✔) |
m | 여러 줄 모드 (^ , $ 가 줄 단위 적용) | /^hello/m | "hello\nworld" → "hello" (✔) |
s | . 이 개행 문자 포함 | /hello.world/s | "hello\nworld" (✔) |
알고리즘 풀이 - 프로그래머스 Lv.2 - [3차] 파일명 정렬
프로그래머스 Lv2. 파일명 정렬
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| function solution(files) {
const answer = [];
for (let file of files) {
let [fileName, head, number] = file.match(/^(\D+)([0-9]+)(.*)$/);
answer.push([fileName, head.toLowerCase(), +number]);
}
answer.sort((a, b) => {
if (a[1] > b[1]) return 1;
else if (a[1] < b[1]) return -1;
else if (a[2] > b[2]) return 1;
else if (a[2] < b[2]) return -1;
});
return answer.map((el) => el[0]);
}
|
정규 표현식 설명
/^ ... $/
^
: 문자열의 시작$
: 문자열의 끝 -> 이 정규식은 문자열 전체가 해당 패턴과 일치해야 함.
(\D+)
\D
: 숫자가 아닌 문자(숫자가 아닌 모든 문자)를 의미합니다.+
: 하나 이상 연속된 문자를 의미합니다. -> 숫자가 아닌 문자로 이루어진 하나 이상의 연속된 문자열
([0-9]+)
[0-9]
: 숫자 (0부터 9까지)+
: 하나 이상의 숫자 -> 연속된 숫자
(.*)
.
: 모든 문자*
: 0개 이상 -> 남은 모든 문자열을 캡처합니다.
Reference
이 포스트는 아래 게시글의 정보 및 이미지가 사용되었습니다.
- 참고 도서 “모던 자바스크립트”
- MDN 정규표현식
- JavaScript 정규 표현식 문법 총정리
END