Python의 re
모듈은 정규 표현식(Regular Expression – Python Document)을 사용하여 문자열 검색, 일치, 대체 등의 작업을 수행하는 데 사용됩니다.
주요 기능
- 패턴 매칭: 특정 문자열 패턴을 찾거나 검사
- 검색 및 대체: 패턴을 기반으로 문자열을 수정
- 문자열 분리: 특정 패턴으로 문자열 분할
정규 표현식 주요 패턴
.
: 임의의 한 문자^
: 문자열 시작$
: 문자열 끝\d
: 숫자\w
: 알파벳/숫자/밑줄+
: 1회 이상 반복*
: 0회 이상 반복[]
: 문자 집합|
: OR 조건
사실 정규 표현식(Regular Expression)의 패턴을 잘 알고 있어도 실제 패턴을 만들어내는 것은 힘들다고 생각합니다.
저도 기존에 사용하던 걸 참조 하고, 수정을 해서 사용을 하지, 패턴을 처음부터 만들어내는 건 잘 안합니다. 일단 시간도 아깝고 어디가 틀렸는지 디버깅이 잘 안되다 보니 기존에 있던 패턴에 추가하거나 변경을 하죠.
이 예제 코드에는 가장 쉽게 볼 수 있는 Card Number를 넣었습니다.
Regular expression Code
import re
# Matching
pattern = r'[34569]\d{3}-\d{4}-\d{4}-\d{4}'
text = "My card number is 9923-2341-2354-2385."
match = re.search(pattern, text)
if match:
print("Match found:", match.group()) # Match found: 9923-2341-2354-2385
else:
print("No match found")
pattern = r'\d+' # Chase only numbers
matches = re.findall(pattern, text)
print("Matches found:", matches) # Matches found: ['9923', '2341', '2354', '2385']
# replace (this is masking)
new_text = re.sub(pattern, '****', text)
print("Replaced text:", new_text)
# Replaced text: My card number is ****-****-****-****.
# group
print(re.match('(23)', text)) # None - First
print(re.search('(23)', text)) # <re.Match object; span=(20, 22), match='23'>
print(re.findall('(23)', text)) # ['23', '23', '23', '23']
print(re.fullmatch('(23)', text)) # None
# capture
pattern = '(\d\d\d\d)'
match = re.findall(pattern, text)
if match:
print(f"{match[0]}-{match[1]}-{match[2]}-{match[3]}") #
else:
print("No match found")
# compile
pattern = re.compile(r'\b\w{2}\b') # 2-letter
matches = pattern.findall(text)
print("2-letter words:", matches) # ['My', 'is']
# Start pattern
pattern_start = r'^My'
if re.match(pattern_start, text):
print("The string starts with 'My'") # The string starts with 'My'
else:
print("The string does not start with 'My'")
# End pattern
pattern_end = r'.$'
if re.search(pattern_end, text):
print("The string ends with '.'") # The string ends with '.'
else:
print("The string does not end with '.'")
# Multiple lines
pattern = r'^\w+' # Fist word
text = """first line
second line
third line"""
matches = re.findall(pattern, text, re.MULTILINE)
print("Words at the start of each line:", matches) # ['first', 'third']
# 비어 있지 않은 줄 찾기
pattern = r'^.+$'
text = """first line
second line
third line
"""
matches = re.findall(pattern, text, re.MULTILINE)
print("Non-empty lines:", matches) # ['first line', ' second line', 'third line']
검색시 속도 이슈로 Complie을 해서 사용하기도 합니다.
Output
Match found: 9923-2341-2354-2385
Matches found: ['9923', '2341', '2354', '2385']
Replaced text: My card number is ****-****-****-****.
None
<re.Match object; span=(20, 22), match='23'>
['23', '23', '23', '23']
None
9923-2341-2354-2385
2-letter words: ['My', 'is']
The string starts with 'My'
The string ends with '.'
Words at the start of each line: ['first', 'third']
Non-empty lines: ['first line', ' second line', 'third line']
요즘에는 개인정보에 대한 보호가 상당히 강한 법률로 보호되다 보니 기업에서도 개인정보에 대해서 신경을 많이 씁니다. 그런데 기업에서 제공을 하고 있는 서비스에서 어디에 개인정보가 있는지 잘 알지 못하는 경우가 많이 있다 보니 기업내부 정보를 탐색하는 제품도 있더군요.
그런데 제가 알기론 이런 패턴으로는 검색으로는 모든 정보를 다 검색 할 수 없어서 패턴과 ML 학습을 통해서 찾는다고 합니다. 근데 생각하며보면 찾는 시간이 상당히 걸리기 때문에 찾는 중에 계속 유입이 될 것 같습니다. 그럼 작고 가벼운 프로그램으로 입력 단에서 막아야되나? 라고 생각을 해보는데 그것도 유입 경로가 너무 많아서 좋은 방법은 아닌 것 같네요.
CISO(최고 정보 관리자)라면 고민을 해야되는 문제이겠죠? 근데 강력한 정책을 적용하면 생산성을 필수적으로 떨어지게 되어 있습니다. 그래서 개인적으로는 생산성과 보안성은 분리된 환경에서 상호 보안적으로 움직여야 되는 것이라 생각하는데 필수적으로 비용이 많이 들어가죠.
뭐 저는 CISO가 아니니 일단 여기까지만 고민해보겠습니다.