♣ Python에서는 re 모듈을 통해 정규 표현식을 사용할 수 있다.
re 모듈의 함수를 호출하여 패턴에 일치하는 문자열을 검색하거나 치환하는 등 다양한 동작을 수행한다.
# python 정규 표현식을 활용한 코드 예제
# 문자열에서 알파벳 대문자만 출력
import re
pattern = re.compile("[A-Z]")
result = pattern.findall("Hello, My name is ODong!")
print(result)
# 결과 : ['H', 'M', 'O', 'D']
♣ re 모듈을 사용하는 순서
1. re 모듈 import
import re
2. 검색할 패턴을 생성하고 객체(변수)를 생성한다.
객체명(변수명) = re.compile("패턴")
3. 객체를 이용하여 문자열을 검색한다.
3-1 객체명.match("전체 문자열")
> 전체 문자열이 패턴으로 일치하는지를 검색한다.(1개의 결과)
> 결과 : <re.Match ...>
3-2 객체명.search("전체 문자열")
> 전체 문자열 내에서 패턴에 처음으로 매치하는 문자열을 검색한다.(1개의 결과)
> 결과 : <re.Match ...>
3-3 객체명.findall("전체 문자열")
> 전체 문자열 내에서 패턴과 일치하는 모든 단어들을 찾아 리스트로 리턴(여러개의 결과)
> 결과 : ['패턴1', '패턴2', '패턴3']
3-4 객체명.finditer("전체 문자열")
> 일치하는 모든 단어들을 찾아 객체들을 모아 리스트화한다. 즉, 모든 문자열 객체를 리스트 형식으로 반환한다.
> 결과 : [<re.Match ...>, <re.Match ...>, <re.Match ...>, ...]
♣ match(문자열) : 전체 문자열의 시작이 패턴과 동일한지를 검색하는 함수이다. 최초로 발견된 1개만 리턴한다.
- 무조건 처음부터 일치해야 한다.
- match()를 이용하여 생성한 객체에 사용할 수 있는 메소드
> group() : 객체에서 찾은 문자열을 리턴
> span() : 전체 문자열에서 패턴이 발견된 시작 인덱스와 종료 인덱스를 리턴
> start() : 패턴이 발견된 시작 인덱스를 리턴
> end() : 패턴이 발견된 종료 인덱스를 리턴
- <...>로 나오는 결과들은 객체를 의미한다.
- start()와 end()는 시작 / 종료 인덱스를 따로 분리하기 위해 사용한다.
♣ search(문자열) : 전체 문자열 내에서 어디에서든지 패턴과 매치되는 문자열이 있으면 찾아낸다. 최초 발견된 1개만 리턴된다.
- 어느 위치에서든지 일치하면 처음 발견된 1개만 찾아준다.
- search()를 이용하여 생성한 객체에 사용할 수 있는 메소드
> group(), span(), start(), end()
- search()는 match()와 다르게 발견된 시작 위치도 알 수 있다.
♣ findall(문자열) : 전체 문자열 내에서 패턴과 매치되는 모든 문자열을 찾아 리스트로 리턴한다.
- 일치하는 모든 패턴을 찾아 리스트로 리턴한다.
♣ 정규 표현식
정규 표현식은 '패턴' 혹은 /패턴/의 형태로 작성한다. /로 패턴을 감싸는 경우, / 뒤에 플래그를 작성할 수 있다.
- 메타 문자 : 문자 그대로 해석되지 않고, 특별한 목적으로 해석되는 문자들을 말한다.
- [] : 문자 클래스라 부르며, [] 안에 있는 각 개별적인 문자들을 or 연산으로 처리한다.
- [^] : ^ 뒤의 패턴을 제외한 나머지와 매치한다.(not)
- \d : 숫자 1문자를 매치한다.([0123456789] 또는 [0-9])
- \D : 숫자가 아닌 1문자를 매치한다.([^0123456789] 또는 [A-Za-z~!@#$%^&*()_+|])
- \w : 숫자, 알파벳(대소문자), _(언더바) 1문자를 매치한다. ID, 변수, DB 필드명 생성 규칙과 동일하다.([0-9A-Za-z_])
- \W : 숫자, 알파벳(대소문자), _(언더바)를 제외한 1문자를 매치한다.([^ 0-9A-Za-z_])
- \s : White Space(Space Bar, Enter, Tab) 1문자를 매치한다. 즉, 공백 문자와 매치한다.([\b\f\n\r\t\v])
- \S : 공백 문자가 아닌 1문자를 매치한다.([^ \b\f\n\r\t\v])
- * : 앞에 나온 문자가 0개 이상이면 매치한다.
- + 앞에 나온 문자가 1개 이상이면 매치한다.
- ? : 앞에 나온 문자가 0개 혹은 1개면 매치한다.
- {n} : 앞에 나온 문자가 n번 반복되면 매치한다.
- {n, } : 앞에 나온 문자가 n번 이상 반복되면 매치한다.
- {n, m} : 앞에 나온 문자가 n번 이상 m번 이하 반복되면 매치한다.(단, n>m)
- () : 괄호로 감싼 부분을 그룹화하여 하나의 문자처럼 여긴다.
import re
url1 = "http://www.ktword.co.kr/index.html"
url2 = "https://www.naver.com/search.html?s=secure"
url3 = "ftp://ftp.kaist.ac.kr"
pat = re.compile("https?://")
print(pat.match(url1))
print(pat.match(url2))
print(pat.match(url3))
# 결과
<re.Match object; span=(0, 7), match='http://'>
<re.Match object; span=(0, 8), match='https://'>
None
# Greedy 수량자 : 기본 정규 표현식의 수량자(*, +, ?, {n} 등)는 탐욕적(Greedy) 수량자에 속한다. 패턴에 더 이상 매치하지 않을 때까지 모두 매치하는 문자열로 인식한다.
# Lazy 수량자 : 기존 수량자의 뒤에 ?를 붙인 형태로, 가능한 적은 문자를 매치한다.
# 정규 표현식 플래그
정규 표현식의 플래그는 검색의 옵션을 지정하는 역할을 한다. 일반적으로 /패턴/플래그 형식으로 작성한다.
- g : global search, 매치하는 모든 문자 또는 문자열을 검색한다.
- i : ignore case, 대소문자를 구분하지 않고 검색한다.
- m : multiline, 여러 줄에서 검색한다.
- s : single line(dotall), 메타 문자 .가 개행 문자도 포함한다.
♣ 컴파일 옵션
python에서 정규 표현식을 컴파일할 때 다음 옵션을 사용할 수 있다.
- IGNORECASE(I) : 대소문자에 상관 없이 매치될 수 있게 한다.
- DOTALL(S) : .(dot)이 \n을 포함해 모든 문자와 매치될 수 있게 한다.
- MULTILINE(M) : ^의 해석을 문자열의 매 행마다 해석한다.
- VERBOSE(X) : verbose 모드를 사용할 수 있게 한다. 어려운 정규식을 주석/줄 단위로 구분되기 한다.
# 사용 방법 : re.DOTALL 또는 re.S
(여러 옵션을 사용할 때는 파이프(|)를 사용하면 된다.)
re.compile("패턴", re.IGNORECASE)
♣ 문자열의 소비가 없는 메타 문자
검색에는 활용하지만 검색 결과에는 포함되지 않는 메타 문자를 의미한다.
- | : 단어단위로 or 연산을 한다.(A|B : A 또는 B)
- ^ : 문자열의 시작 부분부터 검색한다.
- $ : 문자열의 마지막과 일치하는지 검색한다.
- \A : 문자의 시작 부분부터 검색한다. re.MULTILINE 옵션을 무시하고, 문자열의 첫 부분만으로 한정하여 검색한다.
(re.MULTILINE 옵션을 사용하지 않는 ^와 동일하다.) - \Z : re.MULTILINE 옵션을 무시하고 문자열의 마지막 부분만으로 한정하여 검색한다.
(re.MULTILINE 옵션을 사용하지 않는 $와 동일함) - \b : Word Boundary, 단어의 구분자이다. 검색하는 패턴의 앞/뒤 단어를 구분할 수 있는 띄어쓰기, 특수문자 등을 인식하여 검색할 때 사용한다.
- \B : \b의 반대 개념으로, 화이트 스페이스(White Space)로 구분된 단어가 아닌 경우에만 매치된다.
♣ 그루핑(Grouping)
조회된 결과를 세분화하여 일부를 발췌하기 위해 샤용함
- 메타문자 ()로 그룹을 나누며 나누어진 그룹 전체를 0번으로 시작하여 나눈 그룹에 순서가 매겨짐
- 여러개의 그룹으로 나누어진 경우 괄호가 열린 순서대로 그루핑
- 그루핑된 문자열 재참조 : 동일한 단어들이 반복되는 패턴을 찾고 싶을 때 사용한다. '\인덱스번호'로 사용한다.
# 그루핑된 문자열에 이름 붙이기
> 사용법 : (?P<그룹명>패턴)
> 사용자가 원하는 이름을 부여하여 그루핑을 인덱스 대신 구별하여 사용할 수 있다.
> 그룹을 추가할 경우 순서에 대해 생각하지 않아도 이름으로 바로 조회가 가능하다.
# 그루핑된 문자열에 이름 붙이기
(생략)
pat = re.compile(r"(?P<id>\w+)\s(?P<rrn>\d{6}-\d{7})")
print(match.group("id"), match.group("rrn"), sep = "/")
♣ Raw String(r-string)
Raw String은 문자열 앞에 'r'을 붙여 나타낸다. Raw String은 이스케이프 문자를 문자 그대로 인식하는 특수한 문자열이다. 정규 표현식 패턴을 작성할 때 백슬래쉬(\)가 이스케이프 문자로 해석되지 않도록 문자열 맨 앞에 r을 붙여 표현한다.
print("\t" + "Hi")
# 결과 : HI
print(r"\t" + "Hi")
# 결과 :\tHi
♣ 전방 탐색(Lookahead assertions)
특정 문자로 끝나는 문자열을 검색하지만, 결과에는 특정 문자가 포함되지 않기를 원할 때 사용하는 기법
# 긍정형 전방 탐색
> 사용법 : (?=문자열)
> 문자열에 해당하는 정규식과 매치되어야 하며, 조건이 통과되어도 문자열이 소비되지 않는다.
p = re.compile(".+(?=:)")
m = p.search("http://google.com")
print(m.group())
# 결과 : http
# 부정형 전방 탐색
> 사용법 : (?!문자열)
> 문자열에 해당하는 정규식과 매치되지 않아야 하며 조건이 통과되어도 문자열이 소비되지 않는다.
♣ 문자열 바꾸기
# sub() : '원본 문자열'에서 "new문자열'로 바꾸는 메소드
> 사용법 : pattern.sub('new문자열', '원본문자열', count = 수정횟수)
(pattern = re.compile("패턴"))
p = re.compile("(blue|white|red)")
p.sub("color", "blue socks and red shoes")
# 결과 : 'color socks and color shoes'
# subn() : 패턴과 일치하는 문자열을 'new문자열'로 수정 후 '수정된 문자열', 수정개수를 튜로 반환함
p = re.compile("(blue|white|red)")
p.subn("color", "blue socks and red shoes")
# 결과 : ('color socks and color shoes', 2)
♣ JavaScript 정규 표현식
JavaScript에서는 2가지의 방법으로 정규 표현식을 사용한다.
1. 정규 표현식 리터럴 : '/패턴/' 혹은 '/패턴/플래그'의 형태로 작성한다.
2. RegExp 객체 생성 : new RegExp(정규 표현식 리터럴, '플래그') 혹은 new RegExp('패턴', '플래그')로 객체를 생성한다.
♣ 정규 표현식 함수
# pattern.exec(string) : 패턴에 처음으로 매치하는 문자열의 일치 정보를 나타내는 결과 배열을 반환한다.
# pattern.test(string) : 패턴에 매치하는 부분이 있으면 true, 없으면 false를 반환한다.
# string.match(pattern) : 패턴에 매치하는 모든 문자열을 배열 형태로 반환한다.
// 정규 표현식을 활용하여 전체 문자열에서 숫자만 출력
const r = new RegExp(/\d/, 'g');
const str = "H3ll0, DreamH4ck!";
const result = str.match(r);
console.log(result);
// 결과 : ['3', '0', '4']
★ 정규 표현식 연습 도구