Python의 re 모듈은 정규 표현식(Regular Expression – Python Document)을 사용하여 문자열 검색, 일치, 대체 등의 작업을 수행하는 데 사용됩니다.

주요 기능

  1. 패턴 매칭: 특정 문자열 패턴을 찾거나 검사
  2. 검색 및 대체: 패턴을 기반으로 문자열을 수정
  3. 문자열 분리: 특정 패턴으로 문자열 분할

정규 표현식 주요 패턴

  • .: 임의의 한 문자
  • ^: 문자열 시작
  • $: 문자열 끝
  • \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가 아니니 일단 여기까지만 고민해보겠습니다.

By Mark

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다