UB2002's picture
final commmits
a08e3d4
Raw History Blame Contribute Delete
2.63 kB
import re
import spacy
from typing import List, Dict, Tuple
# Load spaCy model for NER (en_core_web_sm)
nlp = spacy.load("en_core_web_sm")
# Regex patterns for PII fields
PATTERNS = {
"email": re.compile(r"[a-zA-Z0-9+._%-]+@[a-zA-Z0-9._%-]+\.[a-zA-Z]{2,6}"),
"phone_number": re.compile(r"\b(?:\+?\d{1,3}[ -]?)?(?:\(\d{3}\)|\d{3})[ -]?\d{3}[ -]?\d{4}\b"),
"dob": re.compile(r"\b\d{2}[/-]\d{2}[/-]\d{4}\b"),
"aadhar_num": re.compile(r"\b\d{4}[ -]?\d{4}[ -]?\d{4}\b"),
"credit_debit_no": re.compile(r"\b\d{4}[ -]?\d{4}[ -]?\d{4}[ -]?\d{4}\b"),
"cvv_no": re.compile(r"\b\d{3}\b"),
"expiry_no": re.compile(r"\b(0[1-9]|1[0-2])\/[0-9]{2}\b"),
}
Entity = Dict[str, object]
def mask_pii(text: str) -> Tuple[str, List[Entity]]:
"""
Masks PII in the text. Returns masked_text and list of entities with their positions and original values.
"""
entities: List[Entity] = []
masked_text = text
# 1) Regex-based masking
for ent_type, pattern in PATTERNS.items():
for match in pattern.finditer(masked_text):
start, end = match.span()
original = match.group()
entities.append({
"position": [start, end],
"classification": ent_type,
"entity": original,
})
masked_text = masked_text[:start] + f"[{ent_type}]" + masked_text[end:]
# 2) spaCy NER for PERSON and DATE
doc = nlp(masked_text)
offset = 0
for ent in doc.ents:
label = ent.label_
if label in ("PERSON", "DATE"):
ent_type = "full_name" if label == "PERSON" else "dob"
start, end = ent.start_char, ent.end_char
original = masked_text[start:end]
entities.append({
"position": [start, end],
"classification": ent_type,
"entity": original,
})
masked_text = masked_text[:start] + f"[{ent_type}]" + masked_text[end:]
# Sort entities by start index
entities.sort(key=lambda x: x["position"][0])
return masked_text, entities
def demask_pii(masked_text: str, entities: List[Entity]) -> str:
"""
Restores original PII values into the masked_text using stored entity list.
"""
result = masked_text
# Apply replacements in reverse order to preserve indices
for ent in sorted(entities, key=lambda x: x["position"][0], reverse=True):
start, end = ent["position"]
original = ent["entity"]
# Replace the [ent_type] placeholder back to original
result = result[:start] + original + result[end:]
return result