Python TIL(13) - 정규표현식

random·2021년 4월 5일
0

Python - TIL

목록 보기
12/19

파이썬 정규표현식 학습기

정규표현식의 기초 다잡기

  • 개념: 정규표현식은 일정한 규칙을 지닌 문자열을 표현하는 방법이다. 대량의 문자열 데이터 내에서 특정한 규칙으로 된 문자열을 검색한 뒤 추출하거나 바꿀 때, 문자열이 정해진 규칙에 맞는지 판단할 때 사용하기에 매우 용이하다.
  • 수행조건: 파이썬 내부에 내장되어있는 re 모듈/라이브러리를 처음에 import 해야지 정규표현식 기능을 실행시킬 수 있다. 또한 원하는 문자열에 'r' 이라는 글자를 선행시켜 (아래 예제 참고) 정규표현식의 기능을 사용할 것을 먼저 선언해야한다.

정규표현식 구성요소:

  • 메타문자: 메타 문자(meta character)란 특별한 뜻이 담겨 있는 문자열 양식을 나타내는 일종의 특수기호이다. 그러므로 어떤 메타 문자가 어떤 의미를 가지고 있는지는 별도로 기억하여야 한다. 보통 추천하는 학습 방법으로 기계적인 암기보다는 많은 실습을 통해 자연스레 숙달시키며 익히는 방법이 권고된다.

*자주 사용하는 메타문자 예시:

메타문자		설명

\d		숫자 [0-9]와 같다.
\D		비숫자 [^0-9]와 같다.
\w		숫자 + 문자 [a-zA-Z0-9]와 같다.
\W		숫자 + 문자가 아닌 것 [^a-zA-Z0-9]와 같다.
\s		공백 [ \t\n\r\f\v]와 같다.
\S		비공백 [^ \t\n\r\f\v]와 같다.
\b		단어 경계 (`\w`와 `\W`의 경계)
\B		비단어 경계

[ ]		문자 클래스
.		\n을 제외한 모든 문자와 매치 (점 하나는 글자 하나를 의미)
*		0회 이상 반복 (업어도 상관 없음)
+		1회 이상 반복 (무조건 한번 이상 등장해야 함)
{m, n}		m회 이상 n회 이하
l		or 조건식을 의미
^		문자열의 시작 의미
$		문자열의 끝을 의미
?		0회 이상 1회 이하
+		1회 이상
\		이스케이프, 또는 메타 문자를 일반 문자로 인식하게 한다
( )		그룹핑, 추출할 패턴을 지정한다.

(?=)		긍정형 전방탐색
(?!)		부정형 전방탐색
(?<=)		긍정형 후방탐색
(?<!)		부정형 후방탐색

<참고: 정규표현식 이메일 작성 예시>

  • re 모듈 내장 메소드:
    (a) re.match: 함수는 문자열의 처음부터 시작하여 패턴이 일치되는 것이 있는지를 확인한다. re.match 함수가 받는 인자는 순서대로 pattern, string, flags이다.
    (b) re.search: re.match와 유사함. 그러나 반드시 문자열의 처음부터 일치할 필요는 없다. re.search 함수는 문자열의 처음뿐 아니라 중간부터라도 패턴과의 일치 부분을 찾아낸다.
    (c) re.findall: 메소드명에서 유추 가능하듯이, re.findall 함수는 문자열 중 찾는 패턴과 일치되는 모든 부분을 찾아낸다.
    (d) re.finditer: re.findall과 유사하지만, 일치된 문자열의 리스트 대신 matchObj 리스트를 반환한다.
    (e) re.fullmatch: re.fullmatch는 문자열이 특정패턴과 비교해 보았을 때, 다른 부분 없이 완벽하게 일치하는지를 확인한다.

정규표현식 사용예제 코드

  • 아래 소스코드는 매우 기초 단계의 정규표현식이니, 다양한 참고자료를 활용하여 정규 표현식을, 머리로만 아는 것이 아니라 실제 써봄으로써 다양한 용법을 숙달 및 체득해야한다!
  • 아래 소스코드 내용과 출력결과와 그에 대한 ('=>' 이후) 세부설명을 함께 보며 기능을 자세히 살펴보자.
<소스코드_1>
import re

print(re.findall(r'at', 'The cat in the hat sat there')) 
print(re.findall(r'.at', 'The cat in the hat sat there'))  
print(re.findall(r'...at', 'The cat in the hat went splat'))  
*출력결과*:

['at', 'at', 'at'] 
=> re.search 메소드를 통해서 'at'과 동일한 글자를 모두 찾아냈다.

['cat', 'hat', 'sat'] 
=> 온점 ' . ' 의 기능 때문에 'at' 앞에 character 한 개가 더 붙은 문자 패턴을 모두 찾아냈다.

['e cat', 'e hat', 'splat'] 
=> 출력결과에 ' . '  앞에 e가 더 붙은 이유는 '...' 이 전, 전전 글자를 다 (White Space 포함) 가르키기 때문이다.

<소스코드_2>
print(re.findall(r'^\d','1 is a number'))  
print(re.findall(r'\d$','The number is 2')) 
*출력결과*:

['1'] 
=> ' ^ ' 의 역할 때문에 숫자로 시작하는 텍스트만 찾음! 

['2'] 
=> ' $ '의 역할 때문에 숫자로 끝나는 텍스트만 찾음! 

<소스코드_3>
phrase = 'there are 5 numbers 37 inside 4 this sentence'
pattern1 = r'[^\d]'  
pattern2 = r'[^\d]+'  

print(re.findall(pattern1, phrase))
print(re.findall(pattern2, phrase))
*출력결과*:

['t', 'h', 'e', 'r', 'e', ' ', 'a', 'r', 'e', ' ', ' ', 'n', 'u', 'm', 'b', 'e', 'r', 's', ' ', ' ', 'i', 'n', 's', 'i', 'd', 'e', ' ', ' ', 't', 'h', 'i', 's', ' ', 's', 'e', 'n', 't', 'e', 'n', 'c', 'e']
=> 숫자가 아닌 모든 글자 하나하나 추출하는 수식

['there are ', ' numbers ', ' inside ', ' this sentence']
=> 바로위 pattern1 처럼 모든 글자를 하나하나 추출하지 않고 숫자가 없는 단어끼리 한데 묶어서 단어 그대로 추출하는 표현 

<소스코드_4>
test_phrase = 'This is a string! But it has punctuation. How can we remove it?'
print(re.findall(r'[^!.?]+', test_phrase)) 

clean = re.findall(r'[^!.? ]+', test_phrase)
print(clean)
print(' '.join(clean))  
*출력결과*: 

['This is a string', ' But it has punctuation', ' How can we remove it']
=> 모든 특수문자 기호 없애는 표현법

['This', 'is', 'a', 'string', 'But', 'it', 'has', 'punctuation', 'How', 'can', 'we', 'remove', 'it']
=> 각 단어별로 잘라서 반환하는 표현법.

This is a string But it has punctuation How can we remove it
=> 바로 윗줄과 비교해보기. 이 라인은 모든 특수기호 없애고 하나의 문장으로 만드는 기능 수행함


<소스코드_5>
text_hypen = 'Only find the hypen-words in this sentence. But you do not know how long-ish they are. 1234567890.'

pattern3 = r'[\w]+'
print(re.findall(pattern3, text_hypen)) 

pattern4 = r'[\w]+-[\w]+'  
#위 patter4에서는 여기서 대괄호를 쓰지 않아도 의도한 코드 결과 도출에는 문제가 없으나, 가독성 향상을 위해서 통상적으로 그루핑을 하며 대괄호를 써준다.
print(re.findall(pattern4,text_hypen)) 
*출력결과*: 

['Only', 'find', 'the', 'hypen', 'words', 'in', 'this', 'sentence', 'But', 'you', 'do', 'not', 'know', 'how', 'long', 'ish', 'they', 'are', '1234567890']
=> Alphanumeric 단어를 추출하는 표현법, 알파벳과 숫자만 정상적으로 추출 및 반환됨.

['hypen-words', 'long-ish']
=> hypen 있는 단어만 추출하는 표현법.


<소스코드_6>
text_one = "catfish"
text_two = "catnap"
text_three = "caterpillar"

print(re.search(r'cat(fish|nap|pillar)', text_one))
print(re.search(r'cat(fish|nap|pillar)', text_two))
print(re.search(r'cat(fish|nap|erpillar)', text_three))
*출력결과*:

re.Match object; span=(0, 7), match='catfish'
re.Match object; span=(0, 6), match='catnap'
re.Match object; span=(0, 11), match='caterpillar'
=> Cat이 붙은 단어를 '|' (또는) 기능 써서 찾는 표현법 

실생활에서 유용한 정규표현식

1) 이메일 :
</^[0-9a-zA-Z]([-_\.]?[0-9a-zA-Z])*@[0-9a-zA-Z]([-_\.]?[0-9a-zA-Z])*\.[a-zA-Z]{2,3}$/i>

  • '시작을' 0~9 사이 숫자 or a-z A-Z 알바펫 아무거나로 시작하고 중간에 - _ . 같은 문자가 있을수도 있고 없을수도 있으며
  • 그 후에 0~9 사이 숫자 or a-z A-Z 알바펫중 하나의 문자가 없거나 연달아 나올수 있으며 / @ 가 반드시 존재하고
  • 0-9a-zA-Z 여기서 하나가 있고 / 중간에 - _ . 같은 문자가 있을수도 있고 없을수도 있으며
  • 그 후에 0~9 사이 숫자 or a-z A-Z 알바펫중 하나의
    문자가 없거나 연달아 나올수 있으며
  • 반드시 . 이 존재하고
  • [a-zA-Z] 의 문자가 2개나 3개가 존재
  • 이 모든것은 대소문자 구분안함

2) 전화번호 : /^\d{3}-\d{3,4}-\d{4}$/

  • 시작을 숫자 3개로하며
  • 중간에 하이픈 - 하나 존재
  • 숫자가 3~4개 존재하며
  • 하이픈 하나 존재
  • 숫자 4개로 끝남

3) 핸드폰 번호 : /^01([0|1|6|7|8|9]?)-?([0-9]{3,4})-?([0-9]{4})$/

  • 시작을 숫자 01로 시작하며 그 후에 0,1,6,7,8,9 중에 하나가 나올수도 있으며
  • 하이픈 - 하나 존재할수도 있으며
  • 숫자 3~4개 이어지고
  • 또 하이픈 - 하나 존재할수도 있으며
  • 숫자 4개가 이어짐

출처: https://hamait.tistory.com/342 [HAMA 블로그]

0개의 댓글