""" 🔄 نرمال‌سازی موجودیت‌ها Entity Normalization for better matching """ import re import logging logger = logging.getLogger(__name__) class EntityNormalizer: """ کلاس برای نرمال‌سازی موجودیت‌های مختلف این کلاس موجودیت‌ها را به فرمت استاندارد تبدیل می‌کند تا: - تطابق دقیق بهتر انجام شود - fuzzy matching موثرتر باشد - از تکرار جلوگیری شود """ def __init__(self): """مقداردهی اولیه normalizer""" logger.info("✅ EntityNormalizer initialized") # نقشه تبدیل اعداد فارسی به انگلیسی self.persian_to_english = str.maketrans('۰۱۲۳۴۵۶۷۸۹', '0123456789') def normalize(self, text: str, entity_type: str) -> str: """ نرمال‌سازی بر اساس نوع موجودیت Args: text: متن اصلی موجودیت entity_type: نوع موجودیت (person/company/amount/percent) Returns: متن نرمال‌شده Examples: >>> normalizer = EntityNormalizer() >>> normalizer.normalize("آقای علی احمدی", "person") 'علی احمدی' >>> normalizer.normalize("۵۰ میلیارد ریال", "amount") '50 میلیارد ریال' """ if not text: return "" # انتخاب متد مناسب بر اساس نوع if entity_type == "person": return self.normalize_person(text) elif entity_type == "company": return self.normalize_company(text) elif entity_type == "amount": return self.normalize_amount(text) elif entity_type == "percent": return self.normalize_percent(text) else: logger.warning(f"⚠️ Unknown entity type: {entity_type}, using basic normalization") return self._basic_normalize(text) def _basic_normalize(self, text: str) -> str: """نرمال‌سازی پایه برای هر متنی""" text = text.strip().lower() text = re.sub(r'\s+', ' ', text) return text def normalize_person(self, text: str) -> str: """ نرمال‌سازی اسامی اشخاص - حذف فضاهای اضافی - lowercase - حذف عناوین (آقای، خانم، دکتر، ...) Args: text: نام شخص Returns: نام نرمال‌شده Examples: >>> normalizer.normalize_person("آقای علی احمدی") 'علی احمدی' >>> normalizer.normalize_person("دکتر مریم کریمی") 'مریم کریمی' """ text = text.strip().lower() # حذف فضاهای اضافی text = re.sub(r'\s+', ' ', text) # حذف عناوین رایج titles = [ 'آقای', 'خانم', 'خانوم', 'دکتر', 'دکتور', 'dr.', 'مهندس', 'استاد', 'اقای', 'جناب', 'سرکار', ] for title in titles: # حذف عنوان از ابتدای متن pattern = rf'^{title}\s+' text = re.sub(pattern, '', text, flags=re.IGNORECASE) return text.strip() def normalize_company(self, text: str) -> str: """ نرمال‌سازی نام شرکت‌ها - حذف فضاهای اضافی - lowercase - استانداردسازی اختصارات (ش. → شرکت) - حذف کلمات اضافی پایانی Args: text: نام شرکت Returns: نام نرمال‌شده Examples: >>> normalizer.normalize_company("ش. پارس") 'شرکت پارس' >>> normalizer.normalize_company("شرکت ملی نفت ایران") 'شرکت ملی نفت' """ text = text.strip().lower() # حذف فضاهای اضافی text = re.sub(r'\s+', ' ', text) # استانداردسازی اختصارات replacements = { 'ش.': 'شرکت', 'ش ': 'شرکت ', 'شرکت‌': 'شرکت', 'بانک‌': 'بانک', 'سازمان‌': 'سازمان', 'موسسه‌': 'موسسه', 'گروه‌': 'گروه', } for old, new in replacements.items(): text = text.replace(old, new) # حذف کلمات اضافی پایانی که معمولاً اختیاری هستند # مثلاً "شرکت ملی نفت ایران" → "شرکت ملی نفت" optional_suffixes = [ r'\s+ایران$', r'\s+تهران$', r'\s+خصوصی$', r'\s+عام$', r'\s+سهامی$', r'\s+سهامی\s+عام$', r'\s+سهامی\s+خاص$', ] for pattern in optional_suffixes: text = re.sub(pattern, '', text) return text.strip() def normalize_amount(self, text: str) -> str: """ نرمال‌سازی مبالغ مالی - تبدیل اعداد فارسی به انگلیسی - حذف فضاهای اضافی - lowercase - استانداردسازی واحدها Args: text: مبلغ مالی Returns: مبلغ نرمال‌شده Examples: >>> normalizer.normalize_amount("۵۰ میلیارد ریال") '50 میلیارد ریال' >>> normalizer.normalize_amount("30 میلیارد تومن") '30 میلیارد تومان' """ # تبدیل اعداد فارسی به انگلیسی text = text.translate(self.persian_to_english) text = text.strip().lower() # حذف فضاهای اضافی text = re.sub(r'\s+', ' ', text) # استانداردسازی واحدهای پولی unit_map = { 'تومن': 'تومان', 'ریآل': 'ریال', 'ريال': 'ریال', 'دالر': 'دلار', 'يورو': 'یورو', } for old, new in unit_map.items(): text = text.replace(old, new) # استانداردسازی واحدهای مقیاس scale_map = { 'ميليارد': 'میلیارد', 'ميليون': 'میلیون', 'هزار': 'هزار', 'تریلیون': 'تریلیون', } for old, new in scale_map.items(): text = text.replace(old, new) # حذف صفات اضافی (مثلاً "ریالی" → "ریال") text = text.replace('ریالی', 'ریال') text = text.replace('تومانی', 'تومان') text = text.replace('دلاری', 'دلار') return text.strip() def normalize_percent(self, text: str) -> str: """ نرمال‌سازی درصدها - تبدیل اعداد فارسی به انگلیسی - یکسان‌سازی علامت درصد (%, ٪ → درصد) - فرمت استاندارد: "عدد درصد" Args: text: درصد Returns: درصد نرمال‌شده Examples: >>> normalizer.normalize_percent("۱۵٪") '15 درصد' >>> normalizer.normalize_percent("20%") '20 درصد' >>> normalizer.normalize_percent("25 درصدی") '25 درصد' """ # تبدیل اعداد فارسی به انگلیسی text = text.translate(self.persian_to_english) text = text.strip() # حذف فضاهای اضافی text = re.sub(r'\s+', ' ', text) # یکسان‌سازی علامت‌های درصد text = text.replace('٪', '%') # تبدیل به فرمت استاندارد: "عدد درصد" # مثال: "15%" → "15 درصد" text = re.sub(r'(\d+(?:\.\d+)?)\s*[%٪]', r'\1 درصد', text) # حذف "درصدی" و تبدیل به "درصد" text = re.sub(r'(\d+(?:\.\d+)?)\s*درصدی', r'\1 درصد', text) return text.strip() # ✅ تست‌های سریع if __name__ == "__main__": print("=" * 60) print("🧪 Testing Normalizer Module") print("=" * 60) normalizer = EntityNormalizer() # تست 1: Person normalization print("\n📊 Test 1: Person Normalization") person_tests = [ "آقای علی احمدی", "دکتر مریم کریمی", "خانم سارا رضایی", "علی محمدی" ] for person in person_tests: normalized = normalizer.normalize_person(person) print(f" '{person}' → '{normalized}'") # تست 2: Company normalization print("\n📊 Test 2: Company Normalization") company_tests = [ "شرکت پارس", "ش. ملی نفت ایران", "شرکت صبا سهامی خاص", "بانک ملی ایران" ] for company in company_tests: normalized = normalizer.normalize_company(company) print(f" '{company}' → '{normalized}'") # تست 3: Amount normalization print("\n📊 Test 3: Amount Normalization") amount_tests = [ "۵۰ میلیارد ریال", "30 میلیارد تومن", "100 میلیارد ریالی", "5 ميليون دلار" ] for amount in amount_tests: normalized = normalizer.normalize_amount(amount) print(f" '{amount}' → '{normalized}'") # تست 4: Percent normalization print("\n📊 Test 4: Percent Normalization") percent_tests = [ "۱۵٪", "20%", "25 درصدی", "30 درصد" ] for percent in percent_tests: normalized = normalizer.normalize_percent(percent) print(f" '{percent}' → '{normalized}'") print("\n" + "=" * 60) print("✅ All tests completed!") print("=" * 60)