ayush678's picture
Upload 8 files
14c6c4f verified
Raw History Blame Contribute Delete
3.47 kB
import re
import random
from typing import Dict
from faker import Faker
class StatefulMapper:
"""
A stateful mapper that generates consistent fake replacements for PII entities.
It stores the mapping of original_text -> fake_text to ensure that if the same
real entity appears multiple times, it is replaced with the exact same fake entity.
"""
def __init__(self, seed: int = None):
"""
Initializes the StatefulMapper.
Args:
seed: An optional integer seed for the Faker instance to ensure
reproducible replacements across runs.
"""
self.fake = Faker()
if seed is not None:
Faker.seed(seed)
random.seed(seed)
# Dictionary structure: { "clean_key": "fake_text" }
self.mappings: Dict[str, str] = {}
def get_replacement(self, entity_type: str, original_text: str) -> str:
"""
Retrieves or generates a fake replacement for the given original text.
Args:
entity_type: The type of the PII entity (e.g., "NAME", "EMAIL").
original_text: The actual PII text found in the document.
Returns:
The fake replacement string.
"""
# Strip honorifics and titles for a consistent base name
clean_text = re.sub(r'\b(mr\.|mrs\.|dr\.|shri|smt\.?)\b', '', original_text, flags=re.IGNORECASE)
# Normalize keys as requested: strip commas, punctuation, spaces
lookup_key = re.sub(r'[^a-z0-9]', '', clean_text.lower())
# Check if we already have a mapping for this entity regardless of type
if lookup_key in self.mappings:
return self.mappings[lookup_key]
# Generate a new fake value based on the entity type
fake_value = self._generate_fake(entity_type, original_text)
# Store for future lookups
self.mappings[lookup_key] = fake_value
return fake_value
def _generate_fake(self, entity_type: str, original_text: str = "") -> str:
"""
Internal method to generate a fake string for a specific entity type.
"""
if entity_type == "NAME":
return self.fake.name()
elif entity_type == "COMPANY":
return self.fake.company()
elif entity_type == "ADDRESS":
# Generate short, concise street and city strings
return self.fake.street_address() + ", " + self.fake.city()
elif entity_type == "EMAIL":
return self.fake.safe_email()
elif entity_type in ("PHONE", "PHONE_KEYWORD"):
# Generating a standard phone format
return self.fake.numerify(text="###-###-####")
elif entity_type == "SSN":
return self.fake.ssn()
elif entity_type == "IP_ADDRESS":
return self.fake.ipv4()
elif entity_type == "CREDIT_CARD":
# Generating a generic 16 digit number to represent CC
return self.fake.credit_card_number(card_type=None)
elif entity_type == "DOB":
# Generate a date of birth (MM/DD/YYYY)
date_obj = self.fake.date_of_birth(minimum_age=18, maximum_age=90)
return date_obj.strftime("%m/%d/%Y")
elif entity_type == "URL":
# Strict generation as per request
return "www." + self.fake.domain_name()
return "[REDACTED]"