Skip to content

bear-bear-bear/learning-regExp

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 

Repository files navigation

learning-regExp 📖

정규 표현식(Regular Expression) 학습 내용 정리


목차

정규표현식의 개요



정규 표현식(Regular Expression)이란 ❔

텍스트에서 특정 패턴을 찾아내는데 사용되는 문자 혹은 기호들의 집합. 약어로 'regEx' 혹은 'regExp', '정규식' 등으로 축약되어 불린다.

정규 표현식은 크게 다음과 같은 역할을 수행한다.

  • 문자 검색(search)
  • 문자 대체(replace)
  • 문자 추출(extract)

위 내용을 기반으로 문자열 내부 텍스트 대체, 포맷의 유효성 검사, 패터 매칭을 기반으로 한 문자열에서 일부 텍스트를 추출, 그리고 그 외 다양한 목적을 위해 사용된다.

하나의 정규 표현식은 단지 텍스트 내부의 검색을 수행하기 위한 문자열의 패턴이다. 예를 들어, 정규 표현식 the는 문자 t 다음에 문자 h, 그 다음 문자 e가 나오는 것을 의미한다.


정규 표현식의 메타 문자 ⚙

메타 문자들은 정규 표현식의 building block들이다. 메타 문자들은 자체적인 의미를 가지지 않고 특별한 방식으로 해석되어지며, 어떠한 메타 문자열들은 특별한 의미를 가지며 대괄호 안에서 쓰인다. 아래는 이러한 메타 문자열들이다.

메타 문자 설명
. 온점(Perido)는 줄바꿈을 제외한 어떤 종류의 단일 문자와 매치
[] 문자 클래스. 대괄호 사이에 있는 문자들로 매치
[^ ] 부정 문자 클래스. 대괄호 안에 포함되지 않은 모든 문자들로 매치
* 이 메타 문자의 바로 앞에 있는 심볼이 0번 이상 반복된 문자들과 매치
+ 이 메타 문자의 바로 앞에 있는 심볼이 1번 이상 반복된 문자들과 매치
? 이 메타 문자의 바로 앞에 있는 심볼을 선택적(optional)으로 만듬
{n, m} 중괄호, 이 메타 문자의 바로 앞에 있는 심볼이 n~m번의 반복된 문자들과 매치
(xyz) 문자 그룹. 문자열 xyz와 정확히 같은 순서를 가진 문자들과 매치
| 대안. 문자가 이 메타 문자의 앞에 있는 심볼이거나 뒤에 있는 심볼이면 매치
\ 다음 문자 이스케이프(Escape). 예약된 문자 [ ( { . * | ^ 등을 이스케이프
^ 입력의 시작과 매치
$ 입력의 끝과 매치

👉 .

마침표(.)는 메타 문자의 가장 간단한 예다. 메타문자 . 는 어떠한 단일 문자와도 매치되지만 리턴 혹은 개행 문자와는 매치되지 않는데. 예를 들어, 정규 표현식 .ar 은 어떠한 단일 문자 다음에 문자 a 가 오고, 그 다음에 문자 r이 오는 패턴을 의미한다.

".ar" => The car parked in the garage.

👉 [ ]

대괄호는 문자 클래스라고도 불리는 문자 집합을 명시하기 위해 사용된다. 문자열 집합 내에 사용된 하이픈은 문자들의 범위를 지정하는데 사용된다. 대괄호 내부에 명시된 문자들의 순서는 중요하지 않다. 예를 들어, 정규 표현식 [Tt]he는 대문자 T 혹은 소문자 t가 나온 다음에, 문자 h가 나오고 그 뒤에 문자 e가 나오는 패턴을 의미한다.

"[Tt]he" => The car parked in the garage.

👉 [^ ]

부정 문자 집합. 일반적으로, 캐럿 기호(^)는 문자열의 시작지점을 나타내지만, 왼쪽 대괄호 바로 뒤에 위치했을때는 해당 문자 집합의 부정(negation)을 나타낸다. 예를 들어, 정규 표현식 [^c]ar은 문자 c를 제외한 어떠한 문자뒤에 문자 a가 오고, 그 뒤에 문자 r이 오는 패턴을 의미한다.

"[^c]ar" => The car parked in the garage.

👉 *

* 부호는 부호 앞에 위치한 매처(matcher)가 0번 이상 반복된 문자열과 매치된다. 정규 표현식 a*은 소문자 a가 0번 이상 반복되는 패턴을 의미한다. 하지만, 만약 이 별 부호가 문자 집합(character set) 직후에 나오는 경우에는 문자 집합 전체의 반복을 찾게된다. 예를 들어, 정규 표현식 [a-z]*은 소문자들이 갯수와 상관없이 연속으로 반복되는 패턴을 의미한다.

"[a-z]*" => The car parked in the garage #21.

* 부호는 메타 문자 .와 함께 모든 문자열과 매치되는 패턴을 만드는데 사용될 수 있다. 또한, * 부호는 공백 문자 \s와 함께 공백 문자들로 이루어진 문자열과 매치되는 패턴을 만드는데 사용될 수 있다. 예를 들어, 정규 표현식 \s*cat\s*는 0번 이상 공백문자가 나온 이후에 소문자 c, 소문자 a, 소문자 t가 자체로 나오고 그 뒤에 다시 0번 이상의 공백문자가 나오는 패턴을 의미한다.

"\scat\s" => The fat cat sat on the concatenation.

👉 +

+ 부호는 부호 앞에 위치한 문자가 한번 이상 반복되는 패턴을 만드는데 사용된다. 예를 들어, 정규 표현식 c.+t는 소문자 c가 나오고, 그 뒤에 한개 이상의 문자가 나온 후, 소문자 t가 나오는 패턴을 의미한다. 여기서 문자 t는 해당 문장의 제일 마지막 글자 t라는것을 명확히할 필요가 있다.

"c.+t" => The fat cat sat on the mat.

👉 ?

정규 표현식에서 메타 문자 ?는 선행 문자를 선택적으로 만드는 역할을 한다. 물음표는 부호 앞에 쓰여진 문자가 선택적으로 나오는 패턴을 나타내는데 사용된다. 예를 들어, 정규 표현식 [T]?he는 대문자 T가 선택적으로 나온 이후에, 그 뒤에 소문자 h, 그 뒤에 소문자 e가 나오는 패턴을 의미한다.

"[T]he" => The car is parked in the garage.

"[T]?he" => The car is parked in the garage.

👉 {n, m}

정규 표현식에서 정량자(quantifier)라고도 불리는 중괄호는 하나의 문자 혹은 문자 집합으로 표시된 문자가 몇번 반복되는지 명시하는데 사용된다. 예를 들어, 정규 표현식 [0-9]{2,3}은 숫자 문자(0부터 9사이의 문자)가 최소 2번, 최대 3번 연속해서 나오는 문자열 패턴을 의미한다.

"[0-9]{2,3}" => The number was 9.9997 but we rounded it off to 10.0.

두번째 숫자를 생략하는 것이 가능하다. 예를 들어, 정규 표현식 [0-9]{2,}는 2번 이상의 숫자가 연속으로 나오는 패턴을 의미한다. 만약 여기서 쉼표를 삭제하는 경우, 정규 표현식 [0-9]{3}은 숫자가 정확히 3번 연속해서 나오는 패턴을 의미한다.

"[0-9]{2,}" => The number was 9.9997 but we rounded it off to 10.0.

"[0-9]{3}" => The number was 9.9997 but we rounded it off to 10.0.

👉 (xyz)

캡쳐링 그룹은 괄호 (...) 안에 쓰여진 하위 패턴들의 그룹이다. 위에서 논의했듯이, 정규 표현식에서 하나의 문자 뒤에 정량자(quantifier)를 넣는 경우에는 해당 문자의 반복을 나타낸다. 하지만, 만약 하나의 캡쳐링 그룹 뒤에 정량자를 넣는 경우에는 캡쳐링 그룹 전체의 반복을 나타내게 된다. 예를 들어, 정규 표현식 (ab)*는 문자 "ab"가 0번 이상 반복되는 패턴을 의미한다. 대안 부호인 | 또한 문자 그룹 내부에서 사용할 수 있다. 예를 들어, 정규 표현식 (c|g|p)ar은 소문자 c, g 혹은 p가 나온 이후에 문자 a가 나오고 그 뒤에 문자 r이 나오는 패턴을 의미한다.

"(c|g|p)ar" => The car is parked in the garage.

캡처링 그룹은 부모 언어에서 사용하기 위해 문자를 일치시킬뿐만 아니라 문자를 캡처한다는 점에 유의해야 한다. 부모 언어는 파이썬이나 자바스크립트 또는 함수 정의에서 정규 표현식을 구현하는 거의 모든 언어가 될 수 있다.

논-캡쳐링 그룹은 오직 문자열에 매칭되지만, 그룹을 캡쳐하지 않는 캡쳐링 그룹이다. 논-캡쳐링 그룹은 (...) 괄호안에 ?: 로 표시된다. 예를 들어 정규식 (?:c|g|p)ar 는 (c|g|p)ar와 같은 문자열을 매칭하는 것에서 유사하지만, 캡쳐링 그룹을 만들지 않는다.

"(?:c|g|p)ar" => The car is parked in the garage.

논-캡처링 그룹은 찾기 및 변경 기능에서 사용하거나 캡처 그룹 함께 사용하여 다른 종류의 출력 생성시 overview를 유지할 때 유용하다.

👉 |

정규 표현식에서 수직 막대 부호 |는 대안을 정의하는데 사용된다. 대안 부호는 여러개의 표현식들 사이의 조건과도 같다. 지금쯤 당신은 문자 집합(Character set)과 대안 부호가 동일하게 동작한다고 생각하고 있을 것이다. 하지만, 문자 집합과 대안 부호 사이의 가장 큰 차이점은 문자 집합은 문자 수준에서 동작하는 반면, 대안 부호는 표현식 수준에서 동작한다는 것이다. 예를 들어, 정규 표현식 (T|t)he|car는 대문자 T 혹은 소문자 t가 나오고 문자h, 문자 e가 차례로 나오거나 문자 c, 문자 a, 문자 r이 차례로 나오는 패턴을 의미한다.

"(T|t)he|car" => The car is parked in the garage.

👉 \

백 슬래시 \는 정규 표현식에서 다음에 나오는 부호를 이스케이핑하는데 사용된다. 백 슬래시는 예약 문자들인 { } [ ] / \ + * . $ ^ | ?를 메타 부호가 아닌 문자 그 자체로 매칭되도록 명시한다. 특수 문자를 매칭 캐릭터로 사용하기 위해서는 백 슬래시 \를 해당 특수 문자 앞에 붙이면 된다. 예를 들어, 정규 표현식 .은 개행을 제외한 어떤 문자와 매칭된다. 입력 문자열에 포함된 . 문자를 매치시키는 정규 표현식 (f|c|m)at\.?은 소문자 f, c 또는 m 이후에 소문자 at가 차례로 등장하고 이후에 문자 .가 선택적으로 나타나는 패턴을 의미한다.

"(f|c|m)at.?" => The fat cat sat on the mat.

👉 ^

캐럿 부호 ^는 매칭 문자가 표현식의 시작이라는 것을 명시하는데 사용된다. 만약 (a가 시작 문자인지 확인하는) 정규 표현식 ^a를 입력 문자열 abc에 적용하면, 이 정규 표현식은 a를 매칭 결과값으로 내보낸다. 반면, 정규 표현식 ^b를 위의 입력 문자열에 적용하면, 아무런 매칭도 일어나지 않는다. 왜냐하면 입력 문자열 abc에서 "b"는 처음 시작 문자가 아니기 때문이다. 또 다른 정규 표현식인 ^(T|t)he를 살펴보자. 이 정규 표현식은 대문자 T 또는 소문자 t가 입력 문자열의 시작으로 나오고, 그 뒤에 문자 h와 문자 e가 차례로 나오는 패턴을 의미한다.

"(T|t)he" => The car is parked in the garage.

"^(T|t)he" => The car is parked in the garage.

👉 $

달러 부호 $는 입력 문자열의 마지막 문자가 매칭 문자로 끝나는지 확인하는데 사용된다. 예를 들어, 정규 표현식 (at.)$는 소문자 a와 t 그리고 문자 .가 순서대로 입력 문자열의 맨 마지막에 나오는지 확인하는 패턴을 의미한다.

"(at.)" => The fat cat. sat. on the mat.

"(at.)$" => The fat cat. sat. on the mat.


단축형 문자열 집합 ✨

정규 표현식은 일반적으로 사용되는 문자열 집합들을 간편하게 사용할 수 있도록 여러 단축형들을 제공한다. 단축형 문자열 집합은 아래와 같다.

단축형 설명
. 개행을 제외한 모든 문자
\w 영숫자 문자와 매치: [a-zA-Z0-9_]
\W 영숫자 문자가 아닌 문자와 매치 [^\w]
\d 숫자와 매치: [0-9]
\D 숫자가 아닌 문자와 매치: [^\d]
\s 공백 문자와 매치: [\t\n\f\r\p{Z}]
\S 공백 문자가 아닌 문자와 매치: [^\s]

전후방탐색 🔎

때때로 전후방탐색Lookaround이라고 알려진 후방탐색Lookbehind과 전방탐색Lookahead은 (패턴 매칭을 위해서 사용되지만 매칭된 리스트에는 포함되지 않는) 논-캡쳐링 그룹 의 특정 종류들이다. 전후방탐색은 하나의 패턴이 다른 특정 패턴 전이나 후에 나타나는 조건을 가지고 있을때 사용한다. 예를 들어, 우리가 입력 문자열 $4.44 and $10.88에 대해서 달러 부호 $이후에 나오는 모든 숫자를 매칭시키고 싶다고 하자. 이때 정규 표현식 (?<=\$)[0-9\.]*를 사용할 수 있다. 이 정규 표현식은 $ 문자 뒤에 나오는 문자 .을 포함한 모든 숫자 문자를 의미한다. 다음은 정규 표현식에서 사용되는 전후방탐색들이다.

부호 설명
?= 긍정형 전방탐색
?! 부정형 전방탐색
?<= 긍정형 후방탐색
?<! 긍정형 후방탐색

👉 ?=

긍정형 전방탐색은 표현식의 첫 부분 뒤에 전방탐색 표현식이 뒤따라 나오는지 확인하는데 사용되며, 매칭의 결과값은 표현식의 첫 부분과 매칭된 텍스트만이 포함된다. 긍정형 전방탐색을 정의하기 위해서는 괄호가 사용된다. 이 괄호 안에서, 물음표 부호 ?와 등호 =가 다음과 같이 사용된다: (?=...). 전방탐색 표현식은 괄호 내부의 등호 = 부호 뒤에 쓰면된다. 예를 들어, 정규 표현식 [T|t]he(?=\sfat)는 대문자 T 혹은 소문자 t 뒤에 문자 h, 문자 e가 나오는 패턴을 의미한다. 괄호 안에서 우리는 정규 표현식 엔진에게 바로 뒤에 공백문자와 문자열 fat이 나오는 The 또는 the만 매치하도록 알리는 긍정형 전방탐색을 정의하였다.

"[T|t]he(?=\sfat)" => The fat cat sat on the mat.

👉 ?!

부정형 전방탐색은 입력 문자열로부터 특정 패턴이 뒤에 나오지 않기를 바라는 상황에서 사용된다. 부정형 전방탐색은 긍정형 전방탐색을 정의하는 방식과 동일하게 정의된다. 유일한 차이점은 등호 부호 = 대신 부정 부호 ! 문자를 사용한다는 것이다, 즉 이렇게 사용한다 (?!...). 정규 표현식 [T|t]he(?!\sfat)를 살펴보도록 하자. 이 정규 표현식은 공백 문자와 fat 문자열이 연속으로 나오지 않는 모든 The 혹은 the 문자열과 매치된다.

"[T|t]he(?!\sfat)" => The fat cat sat on the mat.

👉 ?<=

긍정형 후방탐색은 특정 패턴 뒤에 나오는 문자열 매치를 가져오기 위해서 사용되며, (?<=...)로 표시된다. 예를 들어, 정규 표현식 (?<=[T|t]he\s)(fat|mat)는 입력 문자열에서 The 혹은 the 뒤에 공백이 나오고, 그 뒤에 fat 또는 mat이 나오는 패턴을 의미한다.

"(?<=[T|t]he\s)(fat|mat)" => The fat cat sat on the mat.

👉 ?<!

부정형 후방탐색은 특정 패턴이 뒤에 나오지 않기를 바라는 상황에서 사용되며, (?<!...)로 표시된다. 예를 들어, 정규 표현식 (?<!(T|t)he\s)(cat)은 앞에 The 혹은 the 가 위치하지 않는 모든 cat 문자열을 의미한다.

"(?<![T|t]he\s)(cat)" => The cat sat on cat.


플래그 🚩

플래그는 정규표현식의 출력값을 수정하기 때문에 수정자(modifier)라고도 불린다. 이러한 플래그들은 어떤 순서 혹은 조합으로 사용 가능하며 정규 표현식의 일부분이다.

플래그 설명
i 대소문자 구분없음: 매칭이 대소문자를 구분하지 않도록 설정.
g 전체 검색: 입력 문자열 전체를 대상으로 패턴을 검색.
m 멀티 라인: 앵커 메타 문자(^, &)가 각 줄마다 동작하도록 설정.

👉 i

수정자 i는 대소문자 구분없는 매칭을 수행하는데 사용된다. 예를 들어, 정규 표현식 /The/gi는 대문자 T, 소문자 h, 소문자 e가 차례로 나오는 패턴을 의미한다. 여기서 정규 표현식 마지막에 있는 i 플래그가 정규 표현식 엔진에게 대소문자를 구분하지 않도록 알려준다. g 플래그는 전체 입력 문자열 내부에서 패턴을 검색하기 위해 설정되었다.

"The" => The fat cat sat on the mat.

"/The/gi" => The fat cat sat on the mat.

👉 g

수정자 g는 첫번째 매칭후에 멈추지 않고 계속해서 모든 매칭을 검색하는 전체 검색을 수행하는데 사용된다. 예를 들어, 정규 표현식 /.(at)/g는 개행을 제외한 문자가 나오고, 그 뒤에 소문자 a, 소문자 t가 나오는 패턴을 의미한다. 여기에서 g 플래그를 정규 표현식의 마지막에 설정했기 때문에, 이 패턴은 입력 문자열 전체에서 나타나는 모든 패턴을 찾아낸다.

"/.(at)/" => The fat cat sat on the mat.

"/.(at)/g" => The fat cat sat on the mat.

👉 m

수정자 m은 멀티 라인 매치를 수행하는데 사용된다. 이전에 이야기 했던 것처럼, 앵커 (^, $)는 패턴의 시작과 끝을 확인하는데 사용된다. 하지만 만약 우리가 각 라인마다 이 앵커가 동작하게하고 싶으면 m 플래그를 설정하면된다. 예를 들어, 정규 표현식 /at(.)?$/gm은 소문자 a와 소문자 t가 차례로 나오고, 선택적으로 개행을 제외한 문자가 나오는 패턴을 의미한다. 여기서 플래그 m으로 인해서 정규 표현식 엔진은 입력 문자열의 각 라인에 대해서 해당 패턴을 매칭하게 된다.

"/.at(.)?$/" =>
The fat
cat sat
on the mat.

/.at(.)?$/gm" =>
The fat
cat sat
on the mat.


greedy Match VS Lazy Match 👀

기본적으로 정규 표현식은 greedy하게 매칭을 수행하는데, 이는 가능한 한 길게 매칭하는 것을 의미한다. 우리는 ? 사용하여 lazy하게 매칭할 수 있으며, 가능한 한 짧게 매칭하는 것을 의미한다.

"/(.*at)/" => The fat cat sat on the mat.

"/(.*?at)/" => The fat cat sat on the mat.