정규표현식이란?
: Regular Expression을 줄여서 Regex, Regexp 등으로 불린다. Computer Science의 정규 언어(Regular Language)로부터 유래한 것으로, 특정한 규칙을 가진 문자열의 집합을 표현하기 위해 쓰이는 *형식 언어이다.
=> 어떤 텍스트 내에서 '특정한 형태나 규칙을 가진 문자열' 을 찾기 위해 그 형태나 규칙을 나타내는 패턴을 정의하는 식.
*형식 언어(Formal Language) : 수학, 컴퓨터 과학, 언어학에서 쓰는 말로, 특정한 법칙들에 따라 적절하게 구성된 문자열들의 집합을 말한다.
정규 표현식의 종류 (역사까지?)
정규표현식은 다양한 분야에서 쓰이기 시작했는데, 각 분야의 정규식은 서로 영향을 주고 받으면서 발전했고, 그게 지금의 정규표현식을 만들게 되었다. 여기서 문제는 이러한 정규 표현식에 통일된 표준이 없다는 것이다.
(아니... 이름부터 정규 표현식은데 Regular 한 표준이 없다고...?)
UNIX 시스템의 명령줄 도구들에서 사용하던 정규표현식은 이후에 *POSIX 표준에 편입되었다. 이 시기의 표준으로 받아들여진 형식을 POSIX 정규식이라고 한다.
이후, 다시 POSIX 정규식은 POSIX BRE (Basic Regular Expression)와 POSIX ERE (Extended Regular Expression)으로 나뉘게 된다. (grep -e 스위치를 사용하여 확장 정규식을 쓰게 되는데 이러한 확장 정규식이 ERE를 의미한다.)
그 외에 BRE를 기본 골격으로 한 vim 정규식이 있는데, 이는 vim 에디터 내에서 찾기 또는 바꾸기 등의 동작에서 범위를 지정하는 데에 사용된다. BRE에서 시작됐지만, 오랜 역사를 따라 개선과 확장을 거듭하면서 POSIX 표준과는 조금 다른 규격으로 취급될 정도로 차이가 있다.
이후 문자열을 다루는 데에 특화된 스크립트 언어인 펄(Perl)이 등장했는데, 펄의 정규식 체계 역시 기본 골격은 POSIX BRE를 따르나, 이후 엄청나게 많은 확장이 진행되면서 펄의 정규식은 별도로 PCRE 라는 규격으로 정리되었다. 이후의 많은 프로그래밍 언어들이 이 규격을 차용하거나 계승하는데, 이 역시도 "일부 차용" 이기 때문에, 완전히 PCRE를 계승한다고 볼 수 없다.
(그니까... 어떤 정규식을 사용하는 지에 따라 표현 방법이 다 다를 수 있으니까, 내가 쓰려고 하는 언어나 커맨드에서 어떤 정규식- 버전이 사용되는 지 정확히 찾아봐야 한다는거네...)
*POSIX(포직스, Portable Operating System Interface) 표준 : 서로 다른 UNIX OS의 공통 API를 정리하여, 이식성이 높은 유닉스 응용 프로그램을 개발하기 위한 목적으로 IEEE가 책정한 표준 애플리케이션 인터페이스 규격.
정규표현식 기본 문법
정규 표현식의 기본 문법은 크게 다음과 같이 3가지로 나눌 수 있다.
- 패턴 그대로를 매칭하는 경우 : 편집기에서 '찾기' 기능을 통해 특정 단어를 찾는 것처럼, 단어 그대로를 패턴으로 사용하여 매칭되는 영역을 찾는 방법.
- 메타문자 및 수량 한정자를 사용하는 경우 : 정규식 패턴에 쓰이는 문자 중에는 특별한 의미를 지니는 메타 문자들이 있는데, 이러한 메타문자와 그 메타문자의 개수를 지정(수량 한정자의 역할)하여 폭넓은 패턴을 매칭하는 방법.
- 그룹 및 Look around(전,후방 탐색) 기능을 사용하는 경우 : 제법 고급 정규식이라 할 수 있는 문법으로, 패턴의 일부를 그룹으로 묶거나, 특정 패턴의 앞 또는 뒤로 다른 패턴이 오는 조건을 더하는 경우(Look around 활용)를 말한다.
우선, 정규 표현식의 가장 기본이 되는 메타 문자에 대해서 알아보도록 하자!
정규표현식 메타 문자
: 메타 문자는 특정한 문자 혹은 문자 계열을 대신하여 표시하는 문자로, 메타 문자를 이용하면 특정한 규칙을 가진 여러 단어를 하나의 패턴으로 함축할 수 있다.
참고로 메타문자에서 대소문자는 서로 반대되는 의미를 지니는 경우가 많다!
- ^ : 문자열의 시작을 표현.
ex) ^http : 문자열이 'http'로 시작하는 경우에만 매칭. 문자열 중간에 나타나는 http('ahttps' -> 매칭X)에는 매칭하지 않음.
* [ ... ] 대괄호 안에서 쓰이는 경우라면, ^ 뒤에 오는 문자열 패턴과 일치하지 않는 것을 매칭한다.
ex) ab[^0-9] : 'ab' 뒤에 숫자가 아닌 것이 오는 것만 매칭. (abc -> 매칭O / ab1 -> 매칭X) - $ : 문자열의 끝을 표현.
ex) tem$ : 문자열이 'tem'으로 끝난 경우에만 매칭 ('item' -> 매칭O / 'contemporary' -> 매칭X) - \b : 문자와 공백 사이를 표현. 문자열의 시작, 끝, 개행, 탭, 콤마(','), 구두점('.'), 대시('-') 등이 해당된다.
ex) \bplay\b : 단어 경계로 구분되는 'play'에는 매칭. ('I play the game on the playground' 에서 'play'를 매칭O / 'playground' 는 매칭X) - \B : \b 가 아닌것.
ex) play\B : 'play' 뒤에 단어의 경계가 아닌 것이 올때, 즉 문자열의 연속이 되는 패턴만 매칭.
('I play the game on the playground' 에서 'playground' 를 매칭O / 'play'는 매칭X, 이때 'playground'를 매칭한다고 해서 'playground' 전체를 의미하는 것이 아닌, 'playground' 안의 'play' 만을 찾아낸다.) - \s : 모든 White-space (공백) 문자에 매칭. [\t\n\r\f\v] 와 동일한 의미.
ex) - \S : White-space (공백) 문자를 제외한 모든 문자에 매칭.
- \d : 모든 숫자를 매칭. [0-9] 와 동일한 의미.
- \D : 숫자가 아닌 모든 문자를 매칭. [^0-9] 와 동일한 의미.
- \w : 단어를 만들 수 있는 문자를 매칭. 알파벳 대소문자, 숫자, 언더스코어를 포함. [A-Za-z0-9_] 와 동일한 의미.
- \W : \w에 포함되지 않는 모든 문자를 매칭.
- \n : LF(Line Feed)를 의미. 즉, 엔터(개행문자)를 의미.
참고로 \r 은 CR(Carriage Return)을 의미하는데, UNIX 에서 엔터의 의미를 LF 하나만 쓰는 것으로 보고, Windows에서는 CRLF를 함께 쓰는 것이 엔터를 의미한다. 현대에 와서는 에디터가 알아서 둘다 같이 엔터로 해석시켜 주므로, 엔터를 표현하려고 한다면 그냥 \n 만 사용해도 무방하다. - \ : 이스케이프용 문자. 정규식 상의 특별한 의미를 가지는 문자들을 해당 문자 그대로 사용하고자 할 때 사용하는 문자이다.
ex) \^ : '^' 문자 그대로를 의미. - . : 모든 문자 1개를 매칭. 이때 공백 한칸도 문자 1개로 취급됨.
선택 패턴
- | (Vertical Bar, Pipe) : OR의 의미.
ex) tomato | potato : 'tomato'라는 패턴 또는 'potato'라는 패턴과 일치하는 모든 것들을 매칭한다. - [ ... ] : 대괄호 안의 문자 하나하나들 모두가 OR의 요소로 보면 됨.
ex) [cfh]all : 'call', 'fall', 'hall' 에 모두 매칭. [0-9], [a-z] 와 같이 - 를 활용하여 숫자 전체 또는 알파벳(소문자) 전체 등의 특정 범위를 지정할 수 있음.
수량 한정자
: 동일한 글자 혹은 그룹이 n개 만큼 나오는 경우에 수량 한정자를 뒤에 붙일 수 있다.
- ? : 바로 앞의 글자 혹은 그룹이 1개 혹은 0개 임을 의미.
ex) apples? : ? 바로 앞의 글자인 's'가 있을 수도 있고, 없을 수도 있으므로, 'apple', 'apples' 에 매칭. - * : 0개 이상을 의미.
ex) n\d* : 'n' 뒤에 숫자가 0개 이상이라는 의미. 'n', 'n1', 'n123' 등에 모두 매칭. - + : 1개 이상을 의미.
ex) n\d+ : 'n' 뒤에 숫자가 1개 이상이라는 의미. 'n1', 'n123' 등에 모두 매칭되나, 'n' 에는 매칭되지 않음. - {n} : n 개가 있다는 것을 의미.
ex) n\d{2} : 'n' 뒤 숫자가 2개 오는 패턴을 의미. 'n12' 에는 매칭되나, 'n', 'n1', 'n123' 에는 매칭되지 않음.
'n123' 이라는 문자열에서는 'n12' 까지만 매칭하고, 3은 제외시키게 됨. - {n, m} : n개 이상, m개 이하를 의미. 이때 m을 생략하여 {n, } 와 같이 쓸 수 있는데, 이는 n개 이상 만을 의미.
ex 1) n\d{2, 3} : 'n12', 'n123' 에는 매칭되지만, 'n1'이나 'n1234'에는 매칭되지 않음.
※ 수량한정자의 매칭 방식 : * , + 는 기본적으로 greedy 하게 동작한다. 즉, 가능한 한 많은 글자를 포함하고, 다음 패턴을 찾는다는 말이다. 따라서 . 처럼 모든 문자를 의미하는 메타문자와는 가급적 사용을 하지 않아야 한다. 예를 통해 살펴보자.
ex) 'I like apples and bananas' 에서 ^.*s 를 사용하게 되면, . (아무 문자)의 개수가 제한이 없으므로, ^.*s 를 해석하면, s로 끝나는 가장 긴 문자열이 되게 된다. 즉, 'I like apples and bananas' 그대로 매칭되게 되는 것이다. 이렇게 되면, 정규 표현식을 사용하는 의미가 전혀 없어지게 된다.
그룹
: 소괄호로 둘러싼 단위는 그룹을 나타내는데, 특히 수량 한정자를 그룹에 붙이는 형태로 사용하여, 그룹에 해당하는 패턴이 반복적으로 나타나는 패턴에 대해서 매칭이 가능하게끔 해주는 역할을 한다.
ex 1) (tom|pot)ato : tomato | potato 와 같은 의미. 'tomato' 또는 'potato' 에 모두 매칭되는 패턴을 그룹을 써서 정규식을 좀 더 깔끔하게 표현하였다.
ex 2) (a|i){3}bc : a 혹은 i 가 3개 온 후에 bc가 오는 패턴. aaabc, iiibc, aiabc, aaibc, iiabc 등이 매칭.
전후방탐색
: 반환하지 않을 패턴을 포함하여 Regex의 패턴을 구성하는 것, 즉, 정확한 일치 지점을 찾는 데는 사용되지만 실제 일치하는 부분의 일부로는 사용되지 않는 '어떤 것'이 필요하게 되는데, 이때 사용 되는 것이 Regex의 전후방탐색(Look Around) 기법이다.
■ 전방 탐색(Look Ahead)
- '?=' 사용
- '?=' 다음에 오는 텍스트를 기준으로, 그 이전 텍스트만을 해당 패턴을 적용하여 추출하고자 할 때 사용
ex) '.+(?=:)'
- http://www.co-no_blog.com/
☞ http://www.co-no_blog.com/ - http://mail.co-no.com/
☞ http://mail.co-no.com/ - ftp://ftp.co-no.com/
☞ ftp://ftp.co-no.com/
■ 후방 탐색(Look Behind)
- '?<=' 사용
- '?<=' 다음에 오는 텍스트를 기준으로, 그 이후 텍스트만을 해당 패턴을 적용하여 추출하고자 할 때 사용
ex) '(?<=\$)[0-9.]+'
- ABC01: $23.45
☞ ABC01: $23.45 - HGG42: $5.31
☞ HGG42: $5.31 - CFMX1: $899.00
☞ CFMX1: $899.00 - XTC99: $69.96
☞ XTC99: $69.96
※ 주의사항 : 전방 탐색은 마침표(.)와 더하기(+)를 포함하여 텍스트의 길이를 다양하게 일치시킬 수 있으며, 매우 동적인 반면, 후방 탐색은 보통 일치시킬 텍스트의 길이를 고정해야 한다.
■ 전방탐색과 후방탐색의 동시 사용
다음 예시와 같이 HTML 태그를 제외한 텍스트를 추출하고자 할 때, 전방탐색과 후방탐색의 동시 사용을 유용하게 활용할 수 있다.
ex) '(?<=\<[tT][iI][tT][lL][eE]\>).*(?=<\/[tT][iI][tT][lL][eE]\>)' (\ : 이스케이프 문자)
<head>
<title>co-no의 홈페이지</title>
</head>
■ 부정형 전후방탐색
지금까지 살펴본 전방탐색과 후방탐색의 경우, 반환할 텍스트의 위치, 즉, 찾고자 하는 부분의 앞뒤를 특별히 지정하고 싶을 때 주로 사용하게 된다. 이러한 방식을 긍정형 전방탐색(Positive Lookahead) 또는 긍정형 후방탐색(Positive Lookbehind) 라고 하는데, 여기서 'Positive' 라는 말을 쓰는 이유는, 실제로 일치하는 텍스트를 찾는 방식이기 때문이다.
그렇다면 부정형(Negative) 전후방탐색에 대해 알아보자!
■ 부정형 전방탐색(Negative Lookahead)
- '?!-' 사용
- '?!-' 다음에 오는 텍스트가 붙지 않은, 해당 텍스트 기준의 이전 텍스트 패턴만 적용된 텍스트를 추출하게 된다.
ex) '\d{4}(?!-)'
- 010-1234-5678
☞ 010-1234-5678 - 02-1212-3434
☞ 02-1212-3434
■ 부정형 후방탐색(Negative Lookbehind)
- '?<!' 사용
- '?<!' 다음에 오는 텍스트가 붙지 않은, 해당 텍스트 기준의 이후 텍스트 패턴만 적용된 텍스트를 추출하게 된다.
ex) '\b(?<!\$)\d+\b'
- I paid $30 for 100 apples, 50 oranges, and 60 pears.
☞ I paid $30 for 100 apples, 50 oranges, and 60 pears.
참고
https://junstar92.tistory.com/373
'OS > Linux' 카테고리의 다른 글
[Linux][CentOS 7] vi, vim 테마(colorscheme) 설정 - onehalf (0) | 2023.03.08 |
---|---|
[Linux] CentOS 7 에서 User 생성(useradd)과 User 홈 디렉토리 설정 (0) | 2023.02.28 |
[Linux][쉘스크립트] '$' 의 활용 (1) | 2022.08.23 |
[Linux] 쉘 스크립트 - 파일 존재 여부 확인하기! (0) | 2022.08.17 |
[Linux] ps 결과 항목 설명 및 유용한 ps 예제 (0) | 2022.03.25 |
최근댓글