꼬꼬마 블로그

꼬꼬마의 기술 블로그

손에 잡히는 정규표현식을 읽으며, 정리 (2)

정규표현식 메타 문자, 문자 반복

#RegExp
2022.04.03.

정규표현식 정리 시리즈

메타 문자

정규표현식에는 메타 문자가 존재한다. 대표적인 메타 문자는 .이다.

'hi.'.match(/hi./g); // ['hi.']

.은 위와 같이 문자 .에 대응될 수 있지만 그외의 문자들과도 대응된다.

'hi1'.match(/hi./g); // ['hi1']
이스케이프

그렇다면 진짜 hi.에 해당하는 패턴을 찾고 싶을땐 어떻게 해야할까?

이럴땐 이스케이프자 \(역슬래쉬)를 사용하면 된다.

'hi.'.match(/hi\./g); // ['hi.']
'hi1'.match(/hi\./g); // null

이렇게 \.은 문자 .을 특정하도록 할 수 있다.

공백

줄바꿈이나 탭과 같은 공백 또한 메타문자가 정의되어있다.

`
first
second
third
`.match(/\n/g); // ['\n', '\n', '\n']

\n은 줄바꿈을 나타내며 \t는 탭을 나타낸다.

모든 공백문자의 집합은 \s로 나타낸다. [ \f\n\r\t\v]와 같다.

반대로 공백문자가 아닌 문자는 \S로 나타낸다. [^ \f\n\r\t\v]이다.

숫자

[0-9]는 숫자 하나를 의미한다. 이걸 더 쉽게 표현할 수 있는데 \d로 표현할 수 있다.

'h1 j2 ka'.match(/[hjk]\d/g); // ['h1', 'j2']

반대로 숫자가 아닌 문자 하나 [^0-9]\D로 표한한다.

'h1 j2 ka'.match(/[hjk]\D/g); // ['ka']
알파벳 + 숫자 + _

[a-zA-Z0-9_]를 의미하는 메타문자는 \w이다.

'h1 j2 ka h_ jA k*'.match(/[hjk]\w/g); // ['h1', 'j2', 'ka', 'h_', 'jA']

반대의 경우인 ^[a-zA-Z0-9_]\W로 표현한다.

'h1 j2 ka h_ jA k*'.match(/[hjk]\W/g); // ['k*']

문자의 반복

간단히 http://{name}.com이라는 패턴을 찾고 싶다면 어떻게 해야할까?

'http://a.com'.match(/http:\/\/\w\.com/g); // ['http://a.com']

http://a.com의 경우 잘 찾아진다.

'http://abc.com'.match(/http:\/\/\w\.com/g); // null

다만 http://abc.com은 찾지 못하는데 \w는 하나의 문자에 대응되며 http://{name}.com에서 {name}의 길이는 모르기 때문이다.

이럴땐 + 메타문자를 사용할 수 있다.

'http://a.com'.match(/http:\/\/\w+\.com/g); // ['http://a.com']
'http://abc.com'.match(/http:\/\/\w+\.com/g); // ['http://abc.com']

+ 메타문자는 앞에 나온 집합 혹은 문자의 한번 이상 반복을 의미한다.

반복되는 문자가 없을 수도 있다면?

만약, http://.com과 같은 경우도 찾고 싶다면 어떻게 해야할까?

+ 앞에 나온 집합 혹은 문자가 없을 수 있는 경우는 *로 대체할 수 있다.

*은 앞의 집합 혹은 문자가 없겨나 한번 이상 연속하는 경우에 대응된다.

'http://.com'.match(/http:\/\/\w*\.com/g); // ['http://.com']
'http://a.com'.match(/http:\/\/\w*\.com/g); // ['http://a.com']
'http://abc.com'.match(/http:\/\/\w*\.com/g); // ['http://abc.com']
문자 하나가 없을 수 있다면?

http://{name}.com에서 http와 https 모두 찾고 싶다면 어떻게 해야할까?

'http://abc.com'.match(/https?:\/\/\w*\.com/g); // ['http://abc.com']
'https://abc.com'.match(/https?:\/\/\w*\.com/g); // ['https://abc.com']

? 메타문자를 사용할 수 있다. *과 비슷하지만 ?는 한문자에 대응되며 한 문자가 없거나 한번 존재하는 경우에 사용할 수 있다.

구간 설정

*이나 +는 패턴이 반복되는 횟수와는 무관히 모두 찾을 수 있다. 하지만 특정 횟수에 대응되도록 가져오고 싶다면 {}를 사용할 수 있다.

'hello world'.match(/l\w\w/g); // ['llo']
'hello world'.match(/l\w{2}/g); // ['llo']

l 뒤에 \w가 두번 대응될때 쉽게 생각하면 1번처럼 \w\w를 사용할 수 있지만 \w{2}로도 사용할 수 있다.

{1,2}와 같이 1 ~ 2번으로 정의할 수 있다.

'hello world'.match(/l\w{1,2}/g); // ['llo', 'ld']

또한 최솟값만 존재하도록 할 수 있다.

'hello world'.match(/l\w{2,}/g); // ['llo']
탐욕적, 게으른 수량자
'hello world & hello regex world'.match(/hello.*world/g); // ['hello world & hello regex world']

['hello world', 'hello regex world'] 를 예상했는데 다른 결과가 나왔다.

이건 +, *과 같은 메타문자는 가장 큰 덩어리를 찾으려고 하는데 이걸 *?, +?를 통해 해결할 수 있다.

'hello world & hello regex world'.match(/hello.*?world/g); // ['hello world', 'hello regex world']