javascript 기반으로 작성합니다만, 플래그는 모든 언어에서 비슷하므로 플래그에 대한 이해에는 도움이 될 것입니다.
하단으로 내려갈수록 기존 플래그를 활용하는 부분도 있습니다. 원활한 이해를 위해 플래그 순서대로 읽어주세요!
정규식 패턴에 대한 내용이 궁금하다면 아래 글을 참고하세요.
1. 정규 표현식을 사용하는 방법
정규 표현식 선언 방법
// new RegExp('정규식', '플래그');
let regExp1 = new RegExp('hello', 'g');
// /정규식/플래그;
let regExp2 = /hello/g;
regExp1
new RegExp('정규식', '플래그')는 Javascript에서 사용할 수 있는 객체입니다.regExp2
어느 곳에서나 사용 가능한 정규식을 사용하는 기본 방법은 /정규식/플래그입니다.
정규식에는 우리가 지정할 조건(패턴)이 입력되고,
정규식을 생성할 때 옵션을 지정하는 것이 플래그입니다.
플래그에 대해서는 3번 순서에서 자세히 알아보겠습니다.
간단한 예시로 사용하는 방법에 대해 추가적으로 설명합니다.
예시1) RegExp.test()
let regExp1 = new RegExp('hello', 'g');
var test1 = regExp1.test('Hello, world');
var test2 = regExp1.test('hello, world');
console.log('regExp1 : '+ test1 + ',', test2);
// regExp1 : false, true
var test1 = regExp2.test('Hello, world');
var test2 = regExp2.test('hello, world');
console.log('regExp2 : '+ test1 + ',', test2);
// regExp2 : false, true
해당 정규식을 검색
용도로 활용한 예시입니다. 정규식 조건이 참인지 거짓인지 판별할 수 있습니다.
예시2) String.replace()
let regExp1 = new RegExp('hello', 'g');
var test1 = 'Hello world';
var test2 = 'hello world';
test1 = test1.replace(regExp1, '헬로우');
test2 = test2.replace(regExp1, '헬로우');
console.log(test1); // Hello world
console.log(test2); // 헬로우 world
해당 정규식을 치환
용도로 활용한 예시입니다. 정규식 조건이 참인 경우 지정한 문자열로 치환합니다.
예시3) String.match()
let regExp1 = new RegExp('hello', 'g');
var test1 = 'Hello world';
var test2 = 'hello world';
test1 = test1.match(regExp1);
test2 = test2.match(regExp1);
console.log(test1); // null
console.log(test2); // [ 'hello' ]
정규식 패턴과 일치하면 해당 패턴을 배열에 담아 반환합니다. 만약 일치하는 패턴이 없다면 null을 반환합니다.
2. 플래그란?
여러 프로그래밍 언어에서 정규 표현식을 사용할 때 플래그를 줄 수 있습니다. (언어별로 조금씩 달라요!)
좀 더 다양한 방법으로 정규 표현식의 검색 방식을 설정하기 위해 사용하는 것인데요, Javascript 외의 다른 언어를 사용하시면 개념만 이해하고 각 언어의 사용법에 따라 활용하면 될 것 같습니다.
예제로 좀 더 자세히 알아보겠습니다.
3. 플래그 i
i (Ignore Case) : 대소문자를 구별하지 않는다.
let regExp1 = /hello/;
let regExp2 = /hello/i;
var test1 = regExp1.test('Hello world');
var test2 = regExp2.test('Hello world');
console.log(test1); // false
console.log(test2); // true
test1은 'hello' 와 'Hello'는 일치하지 않기 때문에 결과는 false 입니다.
test2는 플래그(i)를 주었기 때문에 대소문자를 구분하지 않습니다. 그래서 결과는 true 입니다.
4. 플래그 - g
g (Global) : 전역 검색, 문자열 전체에서 패턴을 검색한다.
let regExp1 = /hello/;
let regExp2 = /hello/g;
var test1 = 'hello hello world';
var test2 = 'hello hello world';
test1 = test1.replace(regExp1, '헬로우');
test2 = test2.replace(regExp2, '헬로우');
console.log(test1); // 헬로우 hello world
console.log(test2); // 헬로우 헬로우 world
test1은 처음 발견한 'hello'를 '헬로우'로 치환했습니다.
test2는 플래그(g)를 주었기 때문에 문자열 전체에서 패턴을 검색합니다. 그러므로 문자열 내의 모든 'hello'를 '헬로우'로 치환했습니다.
플래그 여러개를 한 번에 쓸 수도 있어요!
- ig (Ignore Case + Global) : 대소문자를 구별하지 않고, 전역 검색
let regExp1 = /hello/g;
let regExp2 = /hello/gi;
var test1 = 'hello Hello world';
var test2 = 'hello Hello world';
test1 = test1.replace(regExp1, '헬로우');
test2 = test2.replace(regExp2, '헬로우');
console.log(test1); // 헬로우 Hello world
console.log(test2); // 헬로우 헬로우 world
test1은 플래그(g)만 주었기 때문에 두 번째 Hello는 대소문자 구분으로 인해 치환하지 않습니다.
test2는 플래그(ig)를 주었기 때문에 대소문자를 구별하지 않고 모든 hello를 치환했습니다.
5. 플래그 m
m (Multi Line) : 문자열의 행이 여러개일 경우 행 별로 구분해서 패턴을 검색 (각 행 별로 패턴이 있는 경우 사용)
주로 행마다 특정 패턴이 있는 경우 사용합니다.
주로 앵커(`^`, `$`) 또는 전역 플래그(`g`)와 같이 쓰입니다.
앵커(`^`)는 문자열의 시작을 의미합니다.
var test = `
hello hello
hello hello world`;
줄바꿈 되어 있는 문자열 test가 있습니다.
행 마다 문자열의 시작이 'hello'인 경우 '헬로우'로 변경하는 것이 목표입니다.
- 예시1
let regExp1 = /^hello/;
test = test.replace(regExp1, '헬로우');
console.log(test);
hello hello
hello hello world
문자열의 시작이 'hello'인 경우 '헬로우'로 치환하고 싶었습니다만 아무것도 치환되지 않았습니다.
왜냐하면 문자열 test의 시작은 개행이기 때문입니다.
- 예시2
let regExp2 = /^hello/m;
test = test.replace(regExp2, '헬로우');
console.log(test);
헬로우 hello
hello hello world
플래그(m
)을 옵션으로 지정했습니다.
이번에는 '헬로우'로 치환됐지만 한 행만 치환되고 다음 행은 치환되지 않았어요.
- 예시3
let regExp3 = /^hello/mg;
test = test.replace(regExp3, '헬로우');
console.log(test);
헬로우 hello
헬로우 hello world
플래그(mg
)를 옵션으로 지정했습니다.
문자열의 행 마다 'hello'로 시작하는 문자열이 '헬로우'로 치환됐어요.
예시들을 보면 왜 주로 앵커 또는 전역 플래그(g
)와 함께 쓰이는지 알 수 있어요.
6. 플래그 s
s (dotAll) : dot(.
) 문자가 개행(\n)을 포함한 모든 문자에 패턴이 되도록 'dotAll' 모드 활성화
플래그(s
)는 반드시 dot(.
)과 함께 쓰여요!
dot(.
)은 모든 문자를 뜻하는데, 아래 예를 들어 설명할게요.
- dot(.) 예시
var test = 'hello';
let regExp = /./g;
test = test.replace(regExp, '헬로우 ');
console.log(test);
// 헬로우 헬로우 헬로우 헬로우 헬로우
dot(.
)은 모든 문자를 나타낸다고 했어요. 즉, h
, e
, l
, l
, o
각 문자들이 dot(.
) 패턴에 일치하기 때문에 모두 '헬로우'로 치환됩니다.
이제 플래그(s
)를 살펴보면
var test = 'hello hello';
이런 문자열 test가 있다고 가정할게요.
첫 번째 "hello"랑 두 번째 "hello" 사이에 어떤 문자가 올 지 모르는 상황이에요.
그럼 이때 사용하기 좋은 패턴이 바로 dot(.
)이겠죠?
- 예시1) "hello hello"
var test = 'hello hello';
let regExp = /hello.hello/;
test = test.replace(regExp, '헬로우');
console.log(test);
// 헬로우
그런데 이번에는 hello 사이에 개행문자를 넣으면 어떻게 될까요?
- 예시2) "hello\nhello"
var test = 'hello\nhello';
let regExp = /hello.hello/;
test = test.replace(regExp, '헬로우');
console.log(test);
hello
hello
패턴에 일치하지 않아 변환이 되지 않아요.
dot(.
)은 모든 문자에 일치하지만, 개행문자에는 일치하지 않아요.
그러나 플래그(s
) 옵션을 주면 개행문자도 포함시켜준답니다.
- 예시3) 플래그(
s
)
var test = 'hello\nhello';
let regExp = /hello.hello/s;
test = test.replace(regExp, '헬로우');
console.log(test);
// 헬로우
플래그(s
)는 반드시 dot(.
)과 함께 쓰인다는 점을 알고 있으면 될 것 같네요!
7. 플래그 u
u (unicode) : 유니코드 패턴을 사용
4바이트 문자를 2바이트 문자 2개로 처리하지 않고, 문자 1개로 올바르게 처리할 수 있습니다.
그리고 `\p{...}`를 이용해 유니코드 프로퍼티를 패턴으로 사용할 수 있습니다.
예제를 보면 이해하기 쉬울 거예요.
우리가 흔히 쓰는 이모지를 패턴에 사용할 수 있을까요?
- 예시1) 4바이트 이모지를 치환
var test = '😍';
let regExp = /./;
test = test.replace(regExp, '헬로우');
console.log(test);
// 헬로우�
일반적으로 정규식 패턴은 2바이트 기준으로 되어 있습니다.
그런데 문자열 test에 입력된 이모지는 4바이트에요.
그래서 이모지가 2바이트/2바이트 로 분해되어 "헬로우"로 치환되었지만 남은 2바이트는 저렇게 이상한 문자를 표현하게 되는 거죠. 마치 에러처럼요.
이런 문제를 해결하기 위해 플래그(u
)를 사용합니다.
- 예시2) 플래그(
u
)를 사용해 이모지 치환
var test = '😍';
let regExp = /./u;
test = test.replace(regExp, '헬로우');
console.log(test);
// 헬로우
이상한 문자가 남지 않고 이모지가 올바르게 치환된 것을 볼 수 있습니다.
- 예시3-1) 유니코드 프로퍼티에 대한 이해
var test = '$, €, ¥';
이러한 통화($, €, ¥)를 나타내는 문구들이 있죠?
이 통화를 모두 '돈' 이라는 문자로 바꾸려면 어떻게 해야 할까요?
이 때 사용하는 것이 유니코드 프로퍼티입니다.
통화를 나타내는 유니코드 프로퍼티는 \p{Sc}
입니다.
- 예시3-2) 유니코드 프로퍼티를 패턴에 사용
var test = '$, €, ¥';
let regExp = /\p{Sc}/g;
test = test.replace(regExp, '돈');
console.log(test);
// $, €, ¥
통화 유니코드 프로퍼티 \p{Sc}
를 패턴으로 사용하려고 합니다.
그러나 유니코드 프로퍼티를 사용해도 플래그(u
)를 옵션을 주지 않으면 패턴으로 사용할 수 없어요.
- 예시3-3) 플래그(
u
)
var test = '$, €, ¥';
let regExp = /\p{Sc}/gu;
test = test.replace(regExp, '돈');
console.log(test);
// 돈, 돈, 돈
유니코드 프로퍼티에 대한 자세한 설명은 아래 참고자료 링크를 확인하세요.
8. 플래그 y
y (sticky) : 문자 내 특정 위치에서 검색을 진행하는 'sticky' 모드 활성화
플래그(y
)는 반드시 lastIndex 속성과 함께 쓰입니다.
- 예시1 - 문자 내 특정위치를 조회하고 싶은 상황
var test = 'ab?de';
let regExp = /./;
test = test.replace(regExp, '#');
console.log(test);
// #b?de
문자열 test에 3번째 문자에는 무엇이 올 지 모르는 상황이라고 가정할게요.
근데 저는 그 3번째 문자를 #
으로 치환하고 싶어요. 그럼 어떻게 해야 할까요?
다행히도 패턴을 찾을 때 시작 위치를 정해줄 수 있는 방법이 있어요.
- 예시2 - 플래그(
y
) 활용
var test = 'ab?de';
let regExp = /./y;
regExp.lastIndex = 2;
test = test.replace(regExp, '#');
console.log(test);
// ab#de
플래그(y
) 옵션을 주고, 정규식 패턴에 lastIndex 속성에 인덱스 값을 입력하면 해당 인덱스의 문자부터 패턴을 찾습니다.
플래그(y
)의 단점들
- 단점1 - 플래그(
y
)는 플래그(g
)와 함께 쓰면 플래그(g
)와 lastIndex 속성 모두 무시됩니다.
즉, 올바른 결과를 낼 수 없습니다.
var test = 'abcabc';
let regExp = /a/gy;
regExp.lastIndex = 3;
test = test.replace(regExp, '#');
console.log(test);
// #bcabc
보다시피 플래그(g
)도 무시되었고, lastIndex도 무시되었습니다.
- 단점2 - 플래그(
y
)는 해당 위치부터 패턴에 일치하는 것 1개만 찾고 동작을 멈춥니다.
var test = 'abcabcabcabc';
let regExp = /a/y;
regExp.lastIndex = 3;
test = test.replace(regExp, '#');
console.log(test);
// abc#bcabcabc
당연하지만 플래그(g
) 옵션이 무시되므로 전역에서 검색할 수도 없어서 특정 위치부터 패턴에 일치하는 것 1개만 찾을 수 있습니다.
- 단점3 - lastIndex 속성은 일회성입니다.
var test = 'abcabcabcabc';
let regExp = /a/y;
regExp.lastIndex = 3;
var test1 = test.replace(regExp, '#');
console.log(test1);
// abc#bcabcabc
var test2 = test.replace(regExp, '#');
console.log(test2);
// abcabcabcabc
regExp.lastIndex = 3;
var test3 = test.replace(regExp, '#');
console.log(test3);
// abc#bcabcabc
보다시피 똑같은 regExp를 사용해서 치환했지만 두 번째 문자열 test2는 모든 문자 'a'가 치환되지 않았습니다. 일회성이므로 한 번 사용 후 lastIndex 속성은 제거되었기 때문에 아무런 문자도 치환되지 않았습니다.
그러므로 test3처럼 치환하기 전에 다시 lastIndex 속성을 주어야 하는 불편함이 있습니다.
플래그(y
)의 문제를 해결하려면?
전후방탐색을 잘 활용하면 플래그(y
)의 문제들을 해결할 수 있습니다.
관련 내용은 추후 작성하도록 하겠습니다.
9. 참고자료
'Programming > JavaScript' 카테고리의 다른 글
JavaScript 에서 정규식 활용하는 방법들 (0) | 2022.08.11 |
---|---|
예제로 정리한 정규식 패턴 (0) | 2022.08.09 |
Failed to load resource: the server responded with a status of 404 / 404 File not found / sourceMappingURL (2) | 2022.07.20 |
Babel 을 사용해 오류 없는 javascript 코드를 만들자! (0) | 2022.06.10 |
JavaScript: split 공백값 제거하는 여러가지 방법 (0) | 2022.03.10 |