금칙어 필터링 모듈 - 데이터 주입 방식
Project description
sg-word-filter-python
고성능 금칙어 필터링 모듈 (Python) - 정확 일치 및 부분 문자열 검색 지원
✨ 특징
- ⚡ 빠른 검색: Set 기반 O(1) 정확 일치 + Aho-Corasick 부분 문자열 검색
- 🔒 싱글톤 패턴: 앱 라이프사이클 동안 단 한 번만 초기화
- 🛡️ 스레드 안전: Double-checked locking으로 멀티스레드 환경 지원
- 🌐 다국어 지원: UTF-8 완벽 지원 (한글, 영어, 일본어 등)
- 📦 경량: 핵심 기능만 포함 (~15KB)
- 🧪 완벽한 테스트: 100% 코드 커버리지
- 🔤 타입 힌트: 완전한 타입 어노테이션 포함
📦 설치
PyPI (공개 레지스트리)
pip install sg-word-filter-python
GitHub (인하우스)
Git에서 직접 설치
# 최신 버전
pip install git+https://github.com/yourorg/sg-word-filter-python.git
# 특정 버전/태그
pip install git+https://github.com/yourorg/sg-word-filter-python.git@v1.0.0
# 특정 브랜치
pip install git+https://github.com/yourorg/sg-word-filter-python.git@main
GitHub Releases에서 Wheel 설치
pip install https://github.com/yourorg/sg-word-filter-python/releases/download/v1.0.0/sg_word_filter-1.0.0-py3-none-any.whl
requirements.txt에 추가
# Git repository
sg-word-filter-python @ git+https://github.com/yourorg/sg-word-filter-python.git@v1.0.0
# 또는 Release wheel
sg-word-filter-python @ https://github.com/yourorg/sg-word-filter-python/releases/download/v1.0.0/sg_word_filter-1.0.0-py3-none-any.whl
자세한 배포 가이드는 DEPLOY.md를 참조하세요.
🚀 빠른 시작
1. 금칙어 파일 준비 (config/blocklist.json)
["나쁜말", "욕설", "비속어", "금지어"]
2. 모듈 초기화 및 사용
import sg_word_filter
# 애플리케이션 시작 시 초기화 (단 한 번만!)
sg_word_filter.init('./config/blocklist.json')
# ===== 정확 일치 검색 =====
print(sg_word_filter.is_forbidden('나쁜말')) # True
print(sg_word_filter.is_forbidden('정상단어')) # False
# 텍스트에서 금칙어 찾기
words = sg_word_filter.find_forbidden_words('이것은 나쁜말 과 욕설 입니다')
print(words) # ['나쁜말', '욕설']
# 금칙어 포함 여부만 확인
has_bad = sg_word_filter.has_forbidden_words('이것은 나쁜말입니다')
print(has_bad) # True
# ===== 부분 문자열 검색 (Aho-Corasick) =====
results = sg_word_filter.find_forbidden_substrings('나쁜말과욕설입니다')
print(results)
# [
# {'word': '나쁜말', 'index': 0},
# {'word': '욕설', 'index': 5}
# ]
# 부분 문자열 포함 여부
has_substring = sg_word_filter.has_forbidden_substrings('나쁜것')
print(has_substring) # True (금칙어 목록에 "나쁜"이 있다면)
📖 API 레퍼런스
초기화 및 상태 관리
init(filepath, *, silent=False)
금칙어 목록을 파일에서 로드하여 초기화합니다. 앱 라이프사이클 중 단 한 번만 호출되어야 합니다.
sg_word_filter.init('./config/blocklist.json', silent=True)
Parameters:
filepath(str): JSON 배열 형태의 금칙어 파일 경로silent(bool, keyword-only): True일 경우 콘솔 로그 출력 억제 (기본값: False)
Raises:
FilterError: 파일을 찾을 수 없거나, JSON 형식이 잘못되었거나, 배열이 아닌 경우
get_status()
모듈의 현재 상태 정보를 반환합니다.
status = sg_word_filter.get_status()
print(status)
# {
# 'initialized': True,
# 'count': 10,
# 'file_path': '/absolute/path/to/blocklist.json',
# 'loaded_at': '2025-11-18T10:30:00.000000'
# }
Returns: dict - {'initialized', 'count', 'file_path', 'loaded_at'}
reset()
모듈을 초기화 이전 상태로 되돌립니다. 주로 테스트 용도로 사용됩니다.
sg_word_filter.reset()
정확 일치 검색
is_forbidden(word)
단어가 금칙어 목록에 정확히 일치하는지 확인합니다.
sg_word_filter.is_forbidden('나쁜말') # True
sg_word_filter.is_forbidden('나쁜') # False (부분 일치는 False)
Parameters:
word(str): 확인할 단어
Returns: bool
find_forbidden_words(text, *, delimiter=None)
텍스트를 단어 단위로 분리하여 금칙어를 찾습니다.
words = sg_word_filter.find_forbidden_words('나쁜말 과 욕설')
# ['나쁜말', '욕설']
# 사용자 정의 구분자
words2 = sg_word_filter.find_forbidden_words('나쁜말,욕설,정상', delimiter=',')
# ['나쁜말', '욕설']
# 정규표현식 구분자
import re
words3 = sg_word_filter.find_forbidden_words('나쁜말.욕설!정상', delimiter=re.compile(r'[.,!]'))
Parameters:
text(str): 검색할 텍스트delimiter(str|re.Pattern, keyword-only): 단어 구분자 (기본값:r'\s+')
Returns: List[str] - 발견된 금칙어 리스트
has_forbidden_words(text, *, delimiter=None)
텍스트에 금칙어가 포함되어 있는지 확인합니다.
sg_word_filter.has_forbidden_words('이것은 나쁜말입니다') # True
Parameters:
text(str): 검색할 텍스트delimiter(str|re.Pattern, keyword-only):find_forbidden_words()와 동일
Returns: bool
부분 문자열 검색 (Aho-Corasick)
find_forbidden_substrings(text, *, case_sensitive=False)
Aho-Corasick 알고리즘을 사용하여 텍스트에서 금칙어를 부분 문자열로 검색합니다.
# 금칙어 목록: ['나쁜', '욕']
results = sg_word_filter.find_forbidden_substrings('나쁜말과 욕설입니다')
# [
# {'word': '나쁜', 'index': 0},
# {'word': '욕', 'index': 6}
# ]
# 대소문자 구분
results2 = sg_word_filter.find_forbidden_substrings('Bad WORST', case_sensitive=True)
Parameters:
text(str): 검색할 텍스트case_sensitive(bool, keyword-only): 대소문자 구분 여부 (기본값: False)
Returns: List[Dict[str, Any]] - [{'word': str, 'index': int}, ...]
시간 복잡도: O(n + m) - n: 텍스트 길이, m: 매칭 결과 수
has_forbidden_substrings(text, *, case_sensitive=False)
텍스트에 금칙어 부분 문자열이 포함되어 있는지 확인합니다.
# 금칙어 목록: ['나쁜']
sg_word_filter.has_forbidden_substrings('나쁜말') # True
sg_word_filter.has_forbidden_substrings('좋은말') # False
Parameters:
text(str): 검색할 텍스트case_sensitive(bool, keyword-only):find_forbidden_substrings()와 동일
Returns: bool
예외 클래스
FilterError
모듈에서 발생하는 모든 예외는 FilterError 클래스를 사용합니다.
try:
sg_word_filter.init('/invalid/path.json')
except sg_word_filter.FilterError as e:
print(f'에러 코드: {e.code}')
print(f'메시지: {e}')
에러 코드:
FILE_NOT_FOUND: 파일을 찾을 수 없음INVALID_JSON: JSON 파싱 실패INVALID_FORMAT: 배열 형태가 아님NOT_INITIALIZED: 초기화되지 않은 상태에서 함수 호출INVALID_INPUT: 잘못된 입력 타입UNEXPECTED_ERROR: 예상치 못한 오류
🎯 사용 사례
FastAPI 애플리케이션
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
import sg_word_filter
app = FastAPI()
# 앱 시작 시 초기화
@app.on_event("startup")
async def startup_event():
sg_word_filter.init('./config/blocklist.json')
class Comment(BaseModel):
text: str
@app.post("/comment")
async def create_comment(comment: Comment):
bad_words = sg_word_filter.find_forbidden_words(comment.text)
if bad_words:
raise HTTPException(
status_code=400,
detail={
'error': '금칙어가 포함되어 있습니다',
'words': bad_words
}
)
return {'success': True}
Django 미들웨어
# middleware.py
import sg_word_filter
class ProfanityFilterMiddleware:
def __init__(self, get_response):
self.get_response = get_response
sg_word_filter.init('./config/blocklist.json', silent=True)
def __call__(self, request):
if request.method == 'POST' and request.POST.get('comment'):
comment = request.POST['comment']
# 부분 문자열 검색으로 우회 시도 방지
violations = sg_word_filter.find_forbidden_substrings(comment)
if violations:
from django.http import JsonResponse
return JsonResponse({
'error': '메시지에 부적절한 내용이 포함되어 있습니다',
'violations': violations
}, status=400)
response = self.get_response(request)
return response
데코레이터 패턴
import sg_word_filter
from functools import wraps
sg_word_filter.init('./config/blocklist.json', silent=True)
def filter_profanity(func):
@wraps(func)
def wrapper(text, *args, **kwargs):
if sg_word_filter.has_forbidden_words(text):
raise ValueError('텍스트에 금칙어가 포함되어 있습니다')
return func(text, *args, **kwargs)
return wrapper
@filter_profanity
def process_comment(text):
print(f'댓글 처리: {text}')
return True
# 사용
process_comment('정상적인 댓글') # OK
process_comment('나쁜말 포함') # ValueError 발생
🔬 알고리즘 비교
| 기능 | 정확 일치 (Set) | 부분 문자열 (Aho-Corasick) |
|---|---|---|
| 시간 복잡도 | O(1) | O(n + m) |
| 공간 복잡도 | O(k) | O(k * avg_len) |
| 사용 케이스 | "나쁜말" 전체 검출 | "나쁜" → "나쁜말", "나쁜것" 검출 |
| 우회 방지 | 약함 | 강함 |
- k: 금칙어 개수
- n: 텍스트 길이
- m: 매칭 결과 수
- avg_len: 평균 금칙어 길이
📊 성능
# 벤치마크 (10,000개 금칙어, 1,000자 텍스트)
init(): ~40ms (최초 1회만)
is_forbidden(): ~0.001ms (Set lookup)
find_forbidden_words(): ~0.4ms (텍스트 분리 + Set lookup)
find_forbidden_substrings(): ~1.5ms (Aho-Corasick)
🧪 테스트
# 전체 테스트 실행
pytest tests/ -v
# 커버리지 확인
pytest tests/ --cov=sg_word_filter --cov-report=html
# 특정 테스트만 실행
pytest tests/test_filter.py::TestInit -v
💻 개발 환경 설정
# Repository 클론
git clone https://github.com/yourorg/sg-word-filter-python.git
cd sg-word-filter-python
# 가상환경 생성 및 활성화
python -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
# 개발 모드로 설치
pip install -e ".[dev]"
# 테스트 실행
pytest tests/ -v
📝 변경 로그
CHANGELOG.md 참조
🤝 기여
이슈 제기 및 풀 리퀘스트를 환영합니다!
- Fork the Project
- Create your Feature Branch (
git checkout -b feature/AmazingFeature) - Commit your Changes (
git commit -m 'Add some AmazingFeature') - Push to the Branch (
git push origin feature/AmazingFeature) - Open a Pull Request
📄 라이센스
MIT License - LICENSE 파일 참조
👥 관련 프로젝트
- sg-word-filter-node - Node.js 버전
📞 지원
- 🐛 버그 리포트: Issues
- 💬 질문 및 토론: Discussions
- 📧 이메일: dev@yourcompany.com
Made with ❤️ by Your Organization
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file sg_word_filter_python-1.0.1.tar.gz.
File metadata
- Download URL: sg_word_filter_python-1.0.1.tar.gz
- Upload date:
- Size: 15.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.8.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
402003c239532ed95d04f8309f6549f7ccb13c99b978da9b4b17a93adeb874fa
|
|
| MD5 |
3831cb70cee16ca2201c96489f89dfc9
|
|
| BLAKE2b-256 |
3fa61997c20cfd8e0048b1e1c7dd236f18252c945e0a9c245009e13426296cd7
|
File details
Details for the file sg_word_filter_python-1.0.1-py3-none-any.whl.
File metadata
- Download URL: sg_word_filter_python-1.0.1-py3-none-any.whl
- Upload date:
- Size: 14.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.8.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ae72bcb8eff629c5af057b922eb378f26c2c65f237228274553fb1c8ccd0b76b
|
|
| MD5 |
a7fc18a5458148cb2f6e1ea18930dce7
|
|
| BLAKE2b-256 |
d9acb8ba5ea50500945da0a16d42a30184f2a373ab12ba596c2b1b5cbbae202e
|