from normalizer import Normalizer from tokenizer import * # import jalali import re from re import sub import textwrap from html import escape import traceback import re import json import sys,os try: from rapidfuzz import distance from thefuzz import fuzz from bs4 import BeautifulSoup from config_base import * from jalali import Persian except: pass # from lxml import etree import datetime #enumerate(token_list): _normalizer = Normalizer(date_normalizing_needed=True) regex_patterns = { "ref asle N asasi" : r"اصل\s*شماره\s*(\d+)\s*قانون\s*اساسی\s*جمهوری\s*اسلامی\s*ایران", # اصل شماره فلان قانون اساسی جمهوری اسلامی ایران "ref qanone asasi" : r"قانون\sاساسی\sجمهوری\sاسلامی\sایران", # قانون اساسی جمهوری اسلامی ایران که در اول پاراگراف نباشد "ref qanone asasi" : r"قانون\sاساسی", # قانون اساسی که در اول پاراگراف نباشد "ref qanon * mosavvab tarikh": r"قانون(.*?)مصوب\s((y\d{2,4}m\d{1,2}d\d{1,2})|\d{2,4})", # قانون * مصوب تاریخ #"qanon * mosavvab tarikh" : r"قانون[\s\w]*مصوب\s((y\d{2,4}m\d{1,2}d\d{1,2})|\d{2,4})", # قانون * مصوب تاریخ "ref qanone bodje 1" : r"قانون\sبودجه\sسال\s(\d{2,4}|\(\s*\d{2,4}\s*\))\sکل\sکشور", # قانون بودجه سال فلان کل کشور "ref qanone bodje 2" : r"قانون\sبودجه\s(y\d{2,4}m0d0)\stttt\sکل\sکشور", # قانون بودجه سال فلان کل کشور "in qanon" : r"این\sقانون", # این قانون "qanone foq" : r"قانون\sفوق", # قانون فوق "eslahe qanon" : r"قانون\sاصلاح", # اصلاح قانون "tabsare foq" : r"تبصره\sفوق", # تبصره فوق "made foq" : r"ماده\sفوق", # ماده فوق "made vahede" : r"ماده\sواحده", # ماده واحده "made vahed" : r"ماده\sواحد", # ماده واحد "tabsare N" : r"^\bتبصره\s*شماره\s*(\d+)\s*", # تبصره شماره فلان که فقط اول پاراگراف باشد "f tabsare N" : r"(?' tableTag=["table","tr", "th", "tc"] strTable = '' for tag in tableTag: if strTable != '': strTable += '|' strTable += '('+tag+')' regTable = r'<(?P/)*(?P'+strTable+')(?P[^>]+)*>' regTableReplace = r'#[#\g\g\g#]#' def removeHtmlTags(html, exeptionTag=[]): #reg1 = r'<[^>]+>' if exeptionTag.__len__ : exceptTags = '' for tag in exeptionTag: if exceptTags != '': exceptTags += '|' exceptTags += '('+tag+')' reg1 = r'<(?P/)*(?P'+exceptTags+')(?P[^>]+)*>' html = sub(reg1, regTableReplace, html) soup = BeautifulSoup(html, "html.parser") text = soup.get_text("\n", strip=True) if exeptionTag.__len__ : text = sub(mark1, hTag1, text) text = sub(mark2, hTag2, text) return text def removeHtmlNoTableTag(html): html = sub(regTable, regTableReplace, html) soup = BeautifulSoup(html, "html.parser") text = soup.get_text("\n", strip=True) text = sub(mark1, hTag1, text) text = sub(mark2, hTag2, text) return text def normalizerData(data): global _normalizer normalTitle, dates = _normalizer.normalize(data, return_dates=True) tdates = [] for d in dates: if not d.startswith("num"): try: tsd = jdate2timestamp(d) cdate = d except: try: d = d.replace("y", "") d = d.replace("m", "/") d = d.replace("d", "/") m = re.match(r"^(\d{4})\D(\d{1,2})\D(\d{1,2})$", d) if m: [year, month, day] = [ int(m.group(1)), int(m.group(2)), int(m.group(3)), ] if year > 1200 and year < 1550: if month < 1 or month > 12: month = 1 if day < 1 or day > 31: day = 1 cdate = str(year) + "/" + str(month) + "/" + str(day) tsd = jdate2timestamp(cdate) else: # cdate = "1403/03/03" # tsd = jdate2timestamp(cdate) continue else: # cdate = "1403/03/03" # tsd = jdate2timestamp(cdate) continue except: # print("Error in:"+ d +" for id: " + id) # cdate = "1403/03/03" # tsd = jdate2timestamp(cdate) continue tdates.append({"date": cdate, "timestamp": tsd, "index": 0, "slice": ""}) return normalTitle,tdates def normalizerDate2(inputString): global _normalizer normalizedString, dates, recognized_dates, recognized_numbers = _normalizer.normalize(inputString, return_dates=True) tdates = [] for date_item in recognized_dates: date_part = date_item['date'] date_token_index = date_item['date_token_index'] start_date_token_index = date_item['start_date_token_index'] end_date_token_index = date_item['end_date_token_index'] if not date_part.startswith("num"): try: cdate = date_part tsd = jdate2timestamp(date_part) except: try: date_part = date_part.replace("y", "") date_part = date_part.replace("m", "/") date_part = date_part.replace("d", "/") m = re.match(r"^(\d{4})\D(\d{1,2})\D(\d{1,2})$", date_part) if m: [year, month, day] = [ int(m.group(1)), int(m.group(2)), int(m.group(3)), ] if year > 1200 and year < 1550: if month < 1 or month > 12: month = 1 if day < 1 or day > 31: day = 1 cdate = str(year) + "/" + str(month) + "/" + str(day) tsd = jdate2timestamp(cdate) else: # cdate = "1403/03/03" # tsd = jdate2timestamp(cdate) continue # else: # # cdate = "1403/03/03" # # tsd = jdate2timestamp(cdate) # continue except: # print("Error in:"+ d +" for id: " + id) # cdate = "1403/03/03" # tsd = jdate2timestamp(cdate) continue import tokenizer as t inputString_token = t.Tokenizer.tokenize_words(None,inputString) # if start_date_token_index == end_date_token_index: # end_date_token_index += 1 # original_date_part = inputString_token[start_date_token_index:end_date_token_index] # else: original_date_part = inputString_token[start_date_token_index:end_date_token_index + 1] original_date = '' for part in original_date_part: original_date = original_date + ' ' + part original_date = original_date.strip() tdates.append({"converted_date": date_item['date'], "date": cdate , "original_date" : original_date, # "timestamp": tsd, "date_token_index": date_token_index, "start_date_token_index": start_date_token_index, "end_date_token_index":end_date_token_index}) ''' for d in dates: if not d.startswith("num"): try: tsd = jdate2timestamp(d) cdate = d except: try: d = d.replace("y", "") d = d.replace("m", "/") d = d.replace("d", "/") m = re.match(r"^(\d{4})\D(\d{1,2})\D(\d{1,2})$", d) if m: [year, month, day] = [ int(m.group(1)), int(m.group(2)), int(m.group(3)), ] if year > 1200 and year < 1550: if month < 1 or month > 12: month = 1 if day < 1 or day > 31: day = 1 cdate = str(year) + "/" + str(month) + "/" + str(day) tsd = jdate2timestamp(cdate) else: # cdate = "1403/03/03" # tsd = jdate2timestamp(cdate) continue else: # cdate = "1403/03/03" # tsd = jdate2timestamp(cdate) continue except: # print("Error in:"+ d +" for id: " + id) # cdate = "1403/03/03" # tsd = jdate2timestamp(cdate) continue tdates.append({"date": cdate, "timestamp": tsd, "index": 0, "slice": ""})''' return normalizedString,tdates,recognized_numbers def OtherDateFormatNormalizer(inputString,pattern): mainTextTemp = inputString regex_pattern_Mah = r"y(\d{1,4})m(\d{1,2})d(\d{1,2})\sماه\s(\d{1,4})\sو\s(\d{1,3})\sو\s(\d{1,2})\sو\s(\d{1})\s" # y0m4d4 ماه 1000 و 300 و 50 و 4 regex_pattern_MahSal = r"y(\d{1,4})m(\d{1,2})d(\d{1,2})\sماه\sسال\s(\d{1,4})\sو\s(\d{1,3})\sو\s(\d{1,2})\sو\s(\d{1})\s" # y0m4d4 ماه سال 1000 و 300 و 50 و 4 regex_pattern_MahSal2 = r"y(\d{1,4})m(\d{1,2})d(\d{1,2})\sماه\sسال\sy(\d{1,4})m(\d{1,2})d(\d{1,2})\sو\s(\d{1,3})\sو\s(\d{1,2})\sو\s(\d{1})\s" # y0m4d4 ماه سال y1000m0d0 و 300 و 50 و 4 regex_pattern_MahSal3 = r"y(\d{1,4})m(\d{1,2})d(\d{1,2})\sماه\sسال\sy(\d{1,4})m(\d{1,2})d(\d{1,2})" # y0m3d1 ماه سال y1353m0d0 if(pattern==1): regex = re.compile(regex_pattern_Mah) elif(pattern==2): regex = re.compile(regex_pattern_MahSal) elif(pattern==3): regex = re.compile(regex_pattern_MahSal2) elif(pattern==4): regex = re.compile(regex_pattern_MahSal3) matches = regex.finditer(inputString) for match in matches: foundedPattern = match.group() foundedPatternTemp = match.group() if(pattern==1): foundedPattern = foundedPattern.replace('ماه','') else: foundedPattern = foundedPattern.replace('سال','') foundedPattern = foundedPattern.replace('ماه','') foundedPattern = foundedPattern.strip() tempString = foundedPattern standardDatePattern = r"y(\d{1,4})m(\d{1,2})d(\d{1,2})" #regex = re.compile(regex_pattern_Mah) matchItems = re.finditer(standardDatePattern,tempString) for item in matchItems: tempPattern = item.group() tempString = tempString.replace(tempPattern,'') tempString = tempString.strip() tempString = tempString.replace('و','') tempString = tempString.strip() tempArray = tempString.split() year = 0 for item in tempArray: dateMatch = re.finditer(standardDatePattern,item) regexFlag = True for dateItem in dateMatch: yearStr = dateItem.group()[1:5] year += int(yearStr) regexFlag = False break if(item.isalnum() and regexFlag): year += int(item) tempPattern = tempPattern.replace('y0','y'+str(year)) mainTextTemp = mainTextTemp.replace(foundedPatternTemp,tempPattern+' ') return mainTextTemp #foundedPattern = jdate2timestamp(foundedPattern) #convertedText = regex.sub(foundedPattern,convertedText) def normalizerLongData(data): dates = [] if len(data) > 10000: textParts = textwrap.wrap(data, 10000, break_long_words=False) for part in textParts: dates.extend(normalizerData(part)) else: dates = normalizerData(data) return dates # ################## # در ویندوز برای اعداد منفی که تاریخهای قبلی بود را خطا می داد # rr = gdt.timestamp() # ################# def jdate2timestamp_old(dt): ndt = dt.replace("y", "") ndt = ndt.replace("m", "/") ndt = ndt.replace("d", "/") gd = jalali.Persian(ndt).gregorian_datetime() # print(gd) ztime = datetime.time(0, 0, 0, 0) gdt = datetime.datetime.combine(gd, ztime) # print(gdt) rr = gdt.timestamp() tst = int( round(rr) * 1000) return tst def jdate2timestamp(dt): ndt = dt.replace("y", "") ndt = ndt.replace("m", "/") ndt = ndt.replace("d", "/") gd = jalali.Persian(ndt).gregorian_datetime() base = datetime.date(1970, 1, 1) rr = (gd-base).total_seconds() tst = int( round(rr) * 1000) return tst def getSortTimestamp(ts_date): empty_date = -15000000000 ts_ts = empty_date try: if ts_date != "": ts_ts = jdate2timestamp(ts_date) except: ts_ts = empty_date return ts_ts def normalize_content(text): # text = normalYehKe(content) if(text == None) : return '' # جایگزین کردن یک فرمت استاندارد از حروف فارسی به جای فرمت های مختلف فارسی و text = _normalizer.sub_alphabets(text) # کلماتی که با نیم فاصله از هم جدا شده اند، را به هم می چسباند # در این صورت، اگر با یک اسپیس جایگزین شود، یک توکن به متن اصلی اضافه می کند text = sub('\u00A0','',text) text = sub('\u200c','',text) text = sub('\u200F','',text) pattern = r'؟|ʕ|_|ـ'# r',|٬|٫|‚|,|؟|ʕ|،|_|ـ' # خط زیر باعث حذف کاراکتر دش از متن مقررات می شود و در خروجی نهایی، باعث جا به جایی توکن موجودیت های تشخیص داده می شود text = sub(pattern,'', text) return text.strip() def normalYehKe(text): if(text == None) : return '' c1 = sub(yeAr, yeFr, text) c2 = sub(keAr, keFr, c1) c2 = c2.replace('\u00A0', '') return c2.strip() _term_list = [] def setTermList(): global _term_list if(_term_list.__len__() > 0): return _term_list = [ { "begin": jdate2timestamp("1285/07/14"), "end": jdate2timestamp("1287/04/2"), "term": "مجلس شورای ملی-دوره1", "term_number": 1, "majles_name": "شورای ملی", }, { "begin": jdate2timestamp("1288/8/24"), "end": jdate2timestamp("1290/10/3"), "term": "مجلس شورای ملی-دوره2", "term_number": 2, "majles_name": "شورای ملی", }, { "begin": jdate2timestamp("1293/9/14"), "end": jdate2timestamp("1294/8/21"), "term": "مجلس شورای ملی-دوره3", "term_number": 3, "majles_name": "شورای ملی", }, { "begin": jdate2timestamp("1300/4/1"), "end": jdate2timestamp("1302/3/30"), "term": "مجلس شورای ملی-دوره4", "term_number": 4, "majles_name": "شورای ملی", }, { "begin": jdate2timestamp("1302/11/22"), "end": jdate2timestamp("1304/11/22"), "term": "مجلس شورای ملی-دوره5", "term_number": 5, "majles_name": "شورای ملی", }, { "begin": jdate2timestamp("1305/4/19"), "end": jdate2timestamp("1307/5/22"), "term": "مجلس شورای ملی-دوره6", "term_number": 6, "majles_name": "شورای ملی", }, { "begin": jdate2timestamp("1307/7/19"), "end": jdate2timestamp("1309/8/14"), "term": "مجلس شورای ملی-دوره7", "term_number": 7, "majles_name": "شورای ملی", }, { "begin": jdate2timestamp("1309/9/24"), "end": jdate2timestamp("1311/10/24"), "term": "مجلس شورای ملی-دوره8", "term_number": 8, "majles_name": "شورای ملی", }, { "begin": jdate2timestamp("1311/12/24"), "end": jdate2timestamp("1314/1/24"), "term": "مجلس شورای ملی-دوره9", "term_number": 9, "majles_name": "شورای ملی", }, { "begin": jdate2timestamp("1314/3/15"), "end": jdate2timestamp("1316/3/22"), "term": "مجلس شورای ملی-دوره10", "term_number": 10, "majles_name": "شورای ملی", }, { "begin": jdate2timestamp("1316/6/20"), "end": jdate2timestamp("1318/6/27"), "term": "مجلس شورای ملی-دوره11", "term_number": 11, "majles_name": "شورای ملی", }, { "begin": jdate2timestamp("1318/8/3"), "end": jdate2timestamp("1320/8/9"), "term": "مجلس شورای ملی-دوره12", "term_number": 12, "majles_name": "شورای ملی", }, { "begin": jdate2timestamp("1320/8/22"), "end": jdate2timestamp("1322/9/1"), "term": "مجلس شورای ملی-دوره13", "term_number": 13, "majles_name": "شورای ملی", }, { "begin": jdate2timestamp("1322/12/16"), "end": jdate2timestamp("1324/12/21"), "term": "مجلس شورای ملی-دوره14", "term_number": 14, "majles_name": "شورای ملی", }, { "begin": jdate2timestamp("1326/4/25"), "end": jdate2timestamp("1328/5/6"), "term": "مجلس شورای ملی-دوره15", "term_number": 15, "majles_name": "شورای ملی", }, { "begin": jdate2timestamp("1328/11/20"), "end": jdate2timestamp("1330/11/29"), "term": "مجلس شورای ملی-دوره16", "term_number": 16, "majles_name": "شورای ملی", }, { "begin": jdate2timestamp("1331/2/7"), "end": jdate2timestamp("1332/8/28"), "term": "مجلس شورای ملی-دوره17", "term_number": 17, "majles_name": "شورای ملی", }, { "begin": jdate2timestamp("1332/12/27"), "end": jdate2timestamp("1335/1/26"), "term": "مجلس شورای ملی-دوره18", "term_number": 18, "majles_name": "شورای ملی", }, { "begin": jdate2timestamp("1335/3/10"), "end": jdate2timestamp("1339/3/29"), "term": "مجلس شورای ملی-دوره19", "term_number": 19, "majles_name": "شورای ملی", }, { "begin": jdate2timestamp("1339/12/2"), "end": jdate2timestamp("1340/2/19"), "term": "مجلس شورای ملی-دوره20", "term_number": 20, "majles_name": "شورای ملی", }, { "begin": jdate2timestamp("1342/7/14"), "end": jdate2timestamp("1346/7/13"), "term": "مجلس شورای ملی-دوره21", "term_number": 21, "majles_name": "شورای ملی", }, { "begin": jdate2timestamp("1346/7/14"), "end": jdate2timestamp("1350/6/9"), "term": "مجلس شورای ملی-دوره22", "term_number": 22, "majles_name": "شورای ملی", }, { "begin": jdate2timestamp("1350/6/9"), "end": jdate2timestamp("1354/6/16"), "term": "مجلس شورای ملی-دوره23", "term_number": 23, "majles_name": "شورای ملی", }, { "begin": jdate2timestamp("1354/6/17"), "end": jdate2timestamp("1357/11/20"), "term": "مجلس شورای ملی-دوره24", "term_number": 24, "majles_name": "شورای ملی", }, { "begin": jdate2timestamp("1359/3/7"), "end": jdate2timestamp("1363/3/6"), "term": "مجلس شورای اسلامی-دوره1", "term_number": 1, "majles_name": "شورای اسلامی", }, { "begin": jdate2timestamp("1363/3/7"), "end": jdate2timestamp("1367/3/6"), "term": "مجلس شورای اسلامی-دوره2", "term_number": 2, "majles_name": "شورای اسلامی", }, { "begin": jdate2timestamp("1367/3/7"), "end": jdate2timestamp("1371/3/6"), "term": "مجلس شورای اسلامی-دوره3", "term_number": 3, "majles_name": "شورای اسلامی", }, { "begin": jdate2timestamp("1371/3/7"), "end": jdate2timestamp("1375/3/11"), "term": "مجلس شورای اسلامی-دوره4", "term_number": 4, "majles_name": "شورای اسلامی", }, { "begin": jdate2timestamp("1375/3/12"), "end": jdate2timestamp("1379/3/6"), "term": "مجلس شورای اسلامی-دوره5", "term_number": 5, "majles_name": "شورای اسلامی", }, { "begin": jdate2timestamp("1379/3/7"), "end": jdate2timestamp("1383/3/6"), "term": "مجلس شورای اسلامی-دوره6", "term_number": 6, "majles_name": "شورای اسلامی", }, { "begin": jdate2timestamp("1383/3/7"), "end": jdate2timestamp("1387/3/6"), "term": "مجلس شورای اسلامی-دوره7", "term_number": 7, "majles_name": "شورای اسلامی", }, { "begin": jdate2timestamp("1387/3/7"), "end": jdate2timestamp("1391/3/6"), "term": "مجلس شورای اسلامی-دوره8", "term_number": 8, "majles_name": "شورای اسلامی", }, { "begin": jdate2timestamp("1391/3/7"), "end": jdate2timestamp("1395/3/7"), "term": "مجلس شورای اسلامی-دوره9", "term_number": 9, "majles_name": "شورای اسلامی", }, { "begin": jdate2timestamp("1395/3/8"), "end": jdate2timestamp("1399/3/6"), "term": "مجلس شورای اسلامی-دوره10", "term_number": 10, "majles_name": "شورای اسلامی", }, { "begin": jdate2timestamp("1399/3/7"), "end": jdate2timestamp("1403/3/6"), "term": "مجلس شورای اسلامی-دوره11", "term_number": 11, "majles_name": "شورای اسلامی", }, ] def getTermQanon(ts_date_timestamp, ts_ref): setTermList() global _term_list term = "" term_number = 0 majles_name = "" if ts_ref == "هيات وزيران (دوره فترت)": term = ts_ref if ts_ref == "نخست وزير (مصدق)": term = ts_ref if ts_ref == "وزير عدليه (داور)": term = ts_ref if ts_ref == "شوراي انقلاب جمهوري اسلامي ايران": term = ts_ref majles_name = term if term == "": for i in range(len(_term_list) - 1, -1, -1): begin = _term_list[i]["begin"] end = _term_list[i]["end"] if ts_date_timestamp >= begin and ts_date_timestamp <= end: term = _term_list[i]["term"] term_number = _term_list[i]["term_number"] majles_name = _term_list[i]["majles_name"] break error = "" if term == "": # if ts_date_timestamp >= _term_list[0]["begin"] and ts_date_timestamp <= _term_list[len(_term_list)-1]["end"] : if ts_date_timestamp <= _term_list[len(_term_list) - 1]["end"]: for i in range(0, len(_term_list) - 1, 1): end = _term_list[i]["end"] if ts_date_timestamp <= end: term = _term_list[i]["term"] term_number = _term_list[i]["term_number"] majles_name = _term_list[i]["majles_name"] error = "تاریخ بین دو دوره" break else: term_number = -1 error = "تاریخ خارج از محدوده" return term, term_number, majles_name, error # این متد یک متن و ایندکس آغاز و پایان یک عبارت درون آن متن را دریافت می کند # و شماره توکن آغازین و توکن پایانی مربوط به عبارت در متن را بر می گرداند def token_state_finder(normalized_section_content, start_index, end_index): before_substring = normalized_section_content[0:start_index-1].strip() pattern_substring = normalized_section_content[start_index-1:end_index+1].strip() before_substring_token_list = before_substring.strip().split() pattern_token_list = pattern_substring.strip().split() start_token_state = len(before_substring_token_list) end_token_state = len(before_substring_token_list) + (len(pattern_token_list)-1) pattern_tokens_state ={ "start_token_state": start_token_state, "end_token_state" : end_token_state } return pattern_tokens_state def find_number_indexes_in_string(normalized_string,recognized_numbers): complete_recognized_numbers = [] for item in recognized_numbers: number_start_index, number_end_index = find_token_indexes_in_string(normalized_string,item['start_token_index'],item['end_token_index']) content = normalized_string.split() # if item['start_token_index']==item['end_token_index']: # # حذف این بخش و باقی گذاشتن دستور ذیل الز زیر در کفایت درست کار کردن متد بررسی شود # number_token_list = content[item['start_token_index']] # else: number_token_list = content[item['start_token_index']:item['end_token_index']+1] complete_recognized_numbers.append( { 'number_value' : item['number_value'], 'number_token_list' : number_token_list, 'start_token_index' : item['start_token_index'], 'end_token_index' : item['end_token_index'], "start_number_state": number_start_index, "end_number_state" : number_end_index } ) return complete_recognized_numbers # این متد متن اصلی یک متن، توکن آغازین و توکن پایانی مربوط به یک عبارت را می گیرد # و ایندکس آغاز و ایندکس پایان متن وارد شده را بر می گرداند def find_token_indexes_in_string(normalized_string,start_token_state,end_token_state): before_tokens = normalized_string.split()[0:start_token_state] content_tokens = normalized_string.split()[start_token_state:end_token_state + 1] content_start_index = 0 content_end_index = 0 # شمردن تعداد کاراکترهای هر توکن در لیست توکن قبل از عدد for token in before_tokens: content_start_index += len(token) # اضافه کردن تعداد فاصله های خالی یا همان اسپیس به عدد ایندکس شروع عدد content_start_index += len(before_tokens) + 1 # شمردن تعداد کاراکترهای هر توکن در لیست توکن مربوط به عدد for token in content_tokens: content_end_index += len(token) # اضافه کردن تعداد فاصله های خالی یا همان اسپیس به عدد ایندکس پایان عدد content_end_index += (content_start_index - 1) + (len(content_tokens) - 1) return content_start_index, content_end_index # این متد، متنی را دریافت می کند و الگوهای تعریف شده را در آن جستجو می کند و آرایه ای از عبارات مطابق با هر الگو، # شماره ایندکس شروع و پایان هر عبارت، عنوان و محتوای الگو، و شماره توکن شروع و توکن پایانی هر عبارت # پیدا شده را بر می گرداند def regex_patterns_finder(sectoin_content, law_dict): # regex_patterns = { # "ref asle N asasi" : r"اصل\s*شماره\s*(\d+)\s*قانون\s*اساسی\s*جمهوری\s*اسلامی\s*ایران", # اصل شماره فلان قانون اساسی جمهوری اسلامی ایران # "ref qanone asasi" : r"قانون\sاساسی\sجمهوری\sاسلامی\sایران", # قانون اساسی جمهوری اسلامی ایران که در اول پاراگراف نباشد # "ref qanone asasi" : r"قانون\sاساسی", # قانون اساسی که در اول پاراگراف نباشد # "ref qanon * mosavvab tarikh": r"قانون(.*?)مصوب\s((y\d{2,4}m\d{1,2}d\d{1,2})|\d{2,4})", # قانون * مصوب تاریخ # #"qanon * mosavvab tarikh" : r"قانون[\s\w]*مصوب\s((y\d{2,4}m\d{1,2}d\d{1,2})|\d{2,4})", # قانون * مصوب تاریخ # "ref qanone bodje 1" : r"قانون\sبودجه\sسال\s(\d{2,4}|\(\s*\d{2,4}\s*\))\sکل\sکشور", # قانون بودجه سال فلان کل کشور # "ref qanone bodje 2" : r"قانون\sبودجه\s(y\d{2,4}m0d0)\stttt\sکل\sکشور", # قانون بودجه سال فلان کل کشور # "in qanon" : r"این\sقانون", # این قانون # "qanone foq" : r"قانون\sفوق", # قانون فوق # "eslahe qanon" : r"قانون\sاصلاح", # اصلاح قانون # "tabsare foq" : r"تبصره\sفوق", # تبصره فوق # "made foq" : r"ماده\sفوق", # ماده فوق # "made vahede" : r"ماده\sواحده", # ماده واحده # "made vahed" : r"ماده\sواحد", # ماده واحد # "tabsare N" : r"^\bتبصره\s*شماره\s*(\d+)\s*", # تبصره شماره فلان که فقط اول پاراگراف باشد # "f tabsare N" : r"(? 1: # مرتب سازی قانون های پیدا شده بر اساس فاصله کمتر نسبت به متن موردنظر sorted_founded_laws = sorted(founded_laws, key=lambda x: x['Levenshtein_distance'],reverse=True) # از اینجا به بعد بررسی می کنیم که ببینیم کمترین اختلاف با متن مورد نظر چه عددی است # از فاز فاصله صفر شروع می کنیم تا فاز فاصله 4 پیش می رویم # در هر فاز اگر یک مورد عنوان قانونی پیدا شد، همان جواب ماست و شناسه همان را برمیگردانیم # در هر فاز اگر تعداد عناوین پیداشده با فاصله مربوط به آن فاز، بیش از یکی بود، وارد temp_laws = [] for law in sorted_founded_laws: # بررسی فاز فاصله با مقدار صفر # ========================= if int(law['Levenshtein_distance']) == 0: temp_laws.append(law) if len(temp_laws) > 0: if len(temp_laws) == 1: # اگر تنها یک مورد وجود داشت که فاصله آن با متن مورد نظر برابر با مقدار مربوط به این فاز بود، شناسه همان عنوان را بر می گردانیم law_id = temp_laws[0]['law']['id'] return law_id # اگر تعداد عناوین قانونی با فاصله مطابق با مقدار مربوط به این فاز، بیش از یک مورد بود، # مرحله دوم از الگوریتم را پیاده می کنیم # یعنی تعداد عناوین پیدا شده را بر اساس تعداد توکن هر عنوان قانونی مرتب می کنیم elif len(temp_laws) > 1: # مرتب سازی لیست بر اساس تعداد توکن و مقایسه با تعداد توکن متن مورد نظر و انتخاب مورد با کمترین اختلاف temp_laws = find_minimum_token_distance(temp_laws, founded_item_temp) if len(temp_laws) == 1: # اگر فقط یک مورد عنوان قانونی در لیست پیدا شده همان جواب ماست و شناسه آن را بر می گردانیم law_id = temp_laws[0]['law']['id'] return law_id elif len(temp_laws) >1: # این قسمت مرحله سوم الگوریتم است # در مرحله اول، کمترین فاصله لونشتاین را ملاک قرار دادیم # در مرحله دوم، کمترین اختلاف توکن را ملاک قرار دادیم # در این مرحله، لیست باقیمانده را بر اساس تاریخ مرتب می کنیم و شناسه عنوان قانونی که جدیدترین تاریخ را دارد برمی گردانیم # مرتب سازی بر اساس تاریخ و پاپ یک گزینه و استخراج شناسه از همان و برگرداندن آن sorted_strings = sorted(temp_laws, key=lambda x: len(x['law']['approve_date'])) final_row = sorted_strings.pop() law_id = int(final_row['law']['id']) return law_id # اگر هیچ عنوان قانونی را پیدا نکردیم که اختلاف تعداد توکنش با عنوان مورد نظر ما کم باشد # مقدار صفر برگردان else: return 0 # اگر هیچ کدام از عناوین پیدا شده، فاصله ای با مقدار مربوط به این فاز را نداشت، وارد فاز بعدی می شویم، # یعنی اختلاف به جای بررسی اختلاف با مقدار صفر، اختلاف با مقدار یک را بررسی می کنیم elif len(temp_laws) == 0: for law in sorted_founded_laws: # بررسی فاز فاصله با مقدار یک # ========================= if int(law['Levenshtein_distance']) == 1: temp_laws.append(law) if len(temp_laws) > 0: if len(temp_laws) == 1: law_id = temp_laws[0]['law']['id'] return law_id elif len(temp_laws) > 1: # مرتب سازی لیست بر اساس تعداد توکن و مقایسه با تعداد توکن متن مورد نظر و انتخاب مورد با کمترین اختلاف temp_laws = find_minimum_token_distance(temp_laws, founded_item_temp) if len(temp_laws) == 1: return temp_laws[0]['law']['id'] elif len(temp_laws) >1: # مرتب سازی بر اساس تاریخ و پاپ یک گزینه و استخراج شناسه از همان و برگرداندن آن sorted_strings = sorted(temp_laws, key=lambda x: len(x['law']['approve_date'])) final_row = sorted_strings.pop() return int(final_row['law']['id']) else: return 0 elif len(temp_laws) == 0: for law in sorted_founded_laws: # بررسی فاز فاصله با مقدار دو # ========================= if int(law['Levenshtein_distance']) == 2: temp_laws.append(law) if len(temp_laws) > 0: if len(temp_laws) == 1: law_id = temp_laws[0]['law']['id'] return law_id elif len(temp_laws) > 1: # مرتب سازی لیست بر اساس تعداد توکن و مقایسه با تعداد توکن متن مورد نظر و انتخاب مورد با کمترین اختلاف temp_laws = find_minimum_token_distance(temp_laws, founded_item_temp) if len(temp_laws) == 1: return temp_laws[0]['law']['id'] elif len(temp_laws) >1: # مرتب سازی بر اساس تاریخ و پاپ یک گزینه و استخراج شناسه از همان و برگرداندن آن sorted_strings = sorted(temp_laws, key=lambda x: len(x['law']['approve_date'])) final_row = sorted_strings.pop() return int(final_row['law']['id']) else: return 0 elif len(temp_laws) == 0: for law in sorted_founded_laws: # بررسی فاز فاصله با مقدار سه # ========================= if int(law['Levenshtein_distance']) == 3: temp_laws.append(law) if len(temp_laws) > 0: if len(temp_laws) == 1: law_id = temp_laws[0]['law']['id'] return law_id elif len(temp_laws) > 1: # مرتب سازی لیست بر اساس تعداد توکن و مقایسه با تعداد توکن متن مورد نظر و انتخاب مورد با کمترین اختلاف temp_laws = find_minimum_token_distance(temp_laws, founded_item_temp) if len(temp_laws) == 1: return temp_laws[0]['law']['id'] elif len(temp_laws) >1: # مرتب سازی بر اساس تاریخ و پاپ یک گزینه و استخراج شناسه از همان و برگرداندن آن sorted_strings = sorted(temp_laws, key=lambda x: len(x['law']['approve_date'])) final_row = sorted_strings.pop() return int(final_row['law']['id']) else: return 0 elif len(temp_laws) == 0: for law in sorted_founded_laws: # بررسی فاز فاصله با مقدار چهار # ========================= if int(law['Levenshtein_distance']) == 4: temp_laws.append(law) if len(temp_laws) > 0: if len(temp_laws) == 1: law_id = temp_laws[0]['law']['id'] return law_id elif len(temp_laws) > 1: # مرتب سازی لیست بر اساس تعداد توکن و مقایسه با تعداد توکن متن مورد نظر و انتخاب مورد با کمترین اختلاف temp_laws = find_minimum_token_distance(temp_laws, founded_item_temp) if len(temp_laws) == 1: # اگر فقط یک مورد عنوان قانونی در لیست پیدا شده همان جواب ماست و شناسه آن را بر می گردانیم law_id = temp_laws[0]['law']['id'] return law_id elif len(temp_laws) >1: # مرتب سازی بر اساس تاریخ و پاپ یک گزینه و استخراج شناسه از همان و برگرداندن آن sorted_strings = sorted(temp_laws, key=lambda x: len(x['law']['approve_date'])) final_row = sorted_strings.pop() return int(final_row['law']['id']) # اگر هیچ عنوان قانونی را پیدا نکردیم که اختلاف تعداد توکنش با عنوان مورد نظر ما کم باشد else: return 0 # print(99999999999) elif len(founded_laws) == 0: # print(00000000000) law_id = 0 return law_id # اگر تعداد عناوین قانونی مشابه عنوان موردنظر ما که پیدا کردیم فقط یک مورد بود، شناسه همان قانون را برگردان else: # print(11111111111) final_row = founded_laws.pop() law_id = int(final_row['law']['id']) return law_id return law_id # این متد یک لیست از رشته ها و یک رشته را می گیرد و لیست داده شده را براساس کمترین اختلاف توکن نسبت # به تعداد توکن رشته پاس شده به متد، مرتب می کند def find_minimum_token_distance(str_list, caption): str_dict = [] caption_tokens_count = len(caption.split(' ')) # مرتب‌سازی لیست بر اساس تعداد کلمات در caption sorted_strings = sorted(str_list, key=lambda x: len(x['law']['caption'].split())) # اضافه کردن تعداد کلمات مورد نظر به هر دیکشنری for item in sorted_strings: item['token_count'] = len(item['law']['caption'].split()) similar_list = [] for i in range(0,5): for value in sorted_strings: # مقایسه برای پیدا کردن کمترین اختلاف توکن، # از اختلاف صفر شروع می کند تا چهار توکن اختلاف if caption_tokens_count + i == value['token_count']: similar_list.append(value) # در هر مرحله از حلقه، اگر تعداد مقادیر موجود در لیست ما بیش از صفر بود، # همان لیست را برگرداند و حلقه را ادامی ندهد if len(similar_list)>0: return similar_list # در غیر صورت بالا، حلقه را با مقدار ایندکس به علاوه یک ادامه دهد i+=1 return similar_list def change_reference_tokens(normalized_section_content, recognized_patterns_array): token_list = normalized_section_content.strip().split() for ref_item in recognized_patterns_array: if(str(ref_item['type']).__contains__('reference')): start_token_state = ref_item.get('index_start') end_token_state = ref_item.get('index_end') for i in range(start_token_state, end_token_state+1): if i >= len(token_list): break token_list[i] = 'eeee' normalized_section_content = '' for token in token_list: normalized_section_content = ''.join([normalized_section_content, (' ' + token)]) return normalized_section_content.strip() def getMetaData(text, law_dict): text = normalize_content(text) normalized_section_content, recognized_dates, recognized_numbers = normalizerDate2(text.strip()) recognized_numbers = find_number_indexes_in_string(text,recognized_numbers) normalized_section_content = normalized_section_content.strip() recognized_patterns_array = regex_patterns_finder(normalized_section_content, law_dict) nlp_parser = [] date_list = recognized_dates ref_list = recognized_patterns_array for date_item in date_list: nlp_parser.append({ "index_start": int(date_item['start_date_token_index']), "index_end" : int(date_item['end_date_token_index']), "text" : date_item['original_date'], "result" : date_item['converted_date'], #"timestamp" : date_item['timestamp'], "type" : "date", "ref_link" : '' }) for ref_item in ref_list: law_id = int(ref_item['law_id']) nlp_parser.append({ "law_id" : int(ref_item['law_id']), "index_start" : int(ref_item['start_token_state']), "index_end" : int(ref_item['end_token_state']), "text" : ref_item['founded_item'], "result" : ref_item['pattern_value'], "type" : ref_item['pattern_type'], "ref_link" : '' }) return nlp_parser, normalized_section_content def get_ref_parser(content, law_dict): final_found_law = law_title_search(content, law_dict) ref_parser = [] for ref_value in final_found_law: ref_parser.append({ "law_id" : ref_value['law_id'],# شناسه قانون "index_start" : int(ref_value['start_token_index']), "index_end" : int(ref_value['end_token_index']), "text" : ref_value['matched_string'],# توکن هایی که متناظر آنها در عناوین قانون ها وجود داشته "text_tokens" : ref_value['original_string'],# ده توکنی که احتمالا عنوان یک قانون باشد "result" : ref_value['found_law_list'],# لیست عناوین یافت شده "type" : "law_title", "ref_link" : '' }) return ref_parser def save_error(error_text,filename): with open(filename, 'a+', encoding='utf-8') as file: # نوشتن خطا در فایل file.write(error_text + '\n' + 50*'*' + '\n') def save_error(id=0, e=Exception): err_date = datetime.datetime.now() filename = 'ner_reg_errors2.txt' exc_type, exc_value, exc_traceback = sys.exc_info() frame = exc_traceback.tb_frame function_array = traceback.extract_tb(exc_traceback) current_function = function_array[len(function_array)-1] error = f''' id : {id} filename : {current_function.filename} function : {current_function.name} err line no : {current_function.lineno} err line : {current_function.line} err message : {e} err date : {err_date} ''' print( '*'*60 + error + '*'*60) with open(filename, 'a+', encoding='utf-8') as file: # نوشتن خطا در فایل file.write(error + '\n' + 50*'*' + '\n') return error def read_section_table(): cursor, cnxn = create_cursor() query = """SELECT s.ID as section_id,s.SECTIONTEXT as section_text, l.ID as law_id, l.ISLAW as law_islaw from lwSection s left join lwLaw l on s.F_LWLAWID = l.ID where l.ISLAW = 1""" cursor.execute(query) section_list = {} i = 0 for item in cursor.fetchall(): i+=1 if i == 10000:# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! برداشته شود break # if i%1000 == 0: # print(i) #row = cursor.fetchone() id = int(item.section_id) try: text = removeHtmlNoTableTag(item.section_text) except Exception as e: text = item.section_text section_text = normalize_content(text) section_list[id] = {"id": id, "section_text": section_text} cursor.close() cnxn.close() return section_list def read_law_table(): cursor, cnxn = create_cursor() query = """SELECT [ID],[CAPTION],[APPROVEDATE] FROM [Qavanin].[dbo].[lwLaw] where [ISLAW] = 1 order by [APPROVEDATE] desc""" cursor.execute(query) law_dict = {} approve_date_error = [] for item in cursor.fetchall(): #row = cursor.fetchone() id = int(item.ID) caption = normalize_content(item.CAPTION) # تبدیل تاریخ با فرمت رشته به فرمت تاریخ date = str(item.APPROVEDATE).split('/') try: approve_date = Persian(int(date[0]),int(date[1]),int(date[2])) except: approve_date_error.append(date) # در موارد خطا، اپروو دیت کنترل شود law_dict[id] = {"id": id ,"caption": caption,'approve_date': approve_date} cursor.close() cnxn.close() return law_dict def law_recognizer(text, law_dict): i = 0 # try: # nlp_parser, normalized_content = getMetaData(text) # except Exception as e: # save_error(0, e) normalized_content = text text_token_list = normalized_content.strip().split() matched_token_index_list = [] # جمع آوری عناوین احتمالی قانون در یک متن بر اساس کلیدواژه قانون for index,token in enumerate(text_token_list): if 'قانون' in token: matched_token_index_list.append(index) content_token_list = [] law_token_list = [] for index, item in enumerate(matched_token_index_list): # اگر آیتم، آخرین عنصر موجود در آرایه نبود ... if item < len(text_token_list): #content_token_list.append(text_token_list[item]) # نُه توکن بعدی را به عنوان عبارات تکمیلی احتمالی عنوان قانون ذخیره می کنیم if item + 9 < len(text_token_list): for i in range(9): if item + (i+1) >= len(text_token_list): break content_token_list.append(text_token_list[item + (i+1)]) i = 0 # توکن های باقیمانده(که کمتر از نُه توکن است) تا پایان آرایه را ذخیره کن else: j = 0 while j < len(text_token_list)-index: if item + (j+1) >= len(text_token_list)-index: break content_token_list.append(text_token_list[item + (j+1)]) j += 1 j = 0 law_token_list.append({ 'start_token_index': item, 'law_token' : content_token_list }) content_token_list = [] matched_law_list = [] c = 0 for key, law_value in enumerate(law_token_list): c += 1 law_token = law_value['law_token'] start_token_index = law_value['start_token_index'] end_token_index = 0 found_law_list_1 = [] found_law_list_2 = [] found_law_list_3 = [] found_law_list_4 = [] found_law_list_5 = [] found_law_list_6 = [] found_law_list_7 = [] found_law_list_8 = [] found_law_list_9 = [] # اگر تعداد توکن های متنی که احتمالا عنوان یک قانون است، صفر بود، # از حلقه خارج می شویم و به سراغ بررسی عنوان قانون بعدی می رویم if len(law_token) < 1: break # در ابتدا اولین توکن عبارتی که احتمالا عنوان یک قانون است را در عنوان قانون موجود در بانک بررسی می کنیم # در مراحل بعدی تا به نُه گام برسیم، یکی یکی توکن ها را به توکن اول اضافه و سپس با عناوین قانون ها مقایسه می کنیم law_section = law_token[0] for index, value in enumerate(law_dict): # عنوان قانونی که در حال مقایسه متن مورد نظر با آن هستیم id = value['id'] current_caption = value['caption'] current_approve_date = value['approve_date'] # بررسی وجود عبارت مورد نظر در عنوان قانون if current_caption.__contains__(law_section): # به دست آوردن اولین توکن از عنوان قانون current_law_first_token = current_caption.strip().split(' ')[0] # اگر اولین توکن از عنوان قانون برابر با کلمه "قانون" بود، این کلمه را نادیده میگیریم # زیرا در لیست مربوط به لیست توکن های احتمالی مربوط به قوانین، کلمه قانون را در نظر نگرفته ایم if current_law_first_token == 'قانون': current_law_first_token = current_caption.strip().split(' ')[1] if law_section == current_law_first_token: # اگر زیر رشته موردنظر ما در عنوان قانون وجود داشت، نام قانون را در یک لیست ذخیره می کنیم. # در مرحله بعد متن احتمالی قانون که در حال بررسی آن هستیم را با این لیست مقایسه می کنیم تا مقایسه محدود تری داشته باشیم # found_law_list_1.append(current_caption + '#' + str(id) + '#' + current_approve_date) found_law_list_1.append({"id": id ,"caption": current_caption, "approve_date":current_approve_date}) else: continue if len(found_law_list_1) == 0: continue else: if len(found_law_list_1) == 1: found_law = [] found_law.append(found_law_list_1.pop()) k = 0 matched_string = '' found_law_caption = found_law[0]['caption'].strip() if found_law_caption.startswith('قانون'): found_law_caption = found_law_caption[5:] # :متد زیر در ویندوز کار می کند اما در لینوکس کار نمی کند # removeprefix # found_law_caption = found_law[1]['caption'].strip().removeprefix('قانون') found_law_caption_tokens = found_law_caption.strip().split() # if item[0] != 'لازم': for k in range(len(law_token)): if k >= len(found_law_caption_tokens): break if law_token[k] == found_law_caption_tokens[k]: matched_string += law_token[k] + ' ' else: end_token_index = start_token_index + len(matched_string.strip().split()) matched_law_list.append({ "law_id" : found_law[0]['id'], "start_token_index": start_token_index, "end_token_index" : end_token_index, "found_law_list" : found_law, "law_captions" : found_law[0]['caption'], "matched_string" : matched_string.strip(), "original_string" : law_token, "multi_flag" : False }) break end_token_index = start_token_index + len(matched_string.strip().split()) matched_law_list.append({ "law_id" : found_law[0]['id'], "start_token_index" : start_token_index, "end_token_index" : end_token_index, "found_law_list": found_law, "law_captions" : found_law[0]['caption'], "matched_string": matched_string.strip(), "original_string": law_token, "multi_flag": False }) continue # اگر تعداد توکن های متنی که احتمالا عنوان یک قانون است، یکی بود، # از حلقه خارج می شویم و به سراغ بررسی عنوان قانون بعدی می رویم if len(law_token) < 2: continue law_section = law_token[0]+' '+law_token[1] for value in found_law_list_1: id = value['id'] current_caption = value['caption'] current_approve_date = value['approve_date'] rate = fuzz.token_set_ratio(current_caption,law_section) # if current_caption.__contains__(law_section): if rate == 100: # found_law_list_2.append(current_caption + '#' + str(id) + '#' +current_approve_date) found_law_list_2.append({"id": id ,"caption": current_caption, "approve_date":current_approve_date}) if len(found_law_list_2) == 0: # اگر در مرحله قبل بیش از یک مورد پیدا کرده اما در این مرحله تعداد موارد مشابه به صفر رسیده if len(found_law_list_1) > 1 and len(found_law_list_1) < 6: # به دقت کنترل شود # مرتب سازی بر اساس قدیم به جدیدترین شناسه sorted_found_law_list = sorted(found_law_list_1, key=lambda x: x['approve_date']) found_law = sorted_found_law_list.pop() end_token_index = start_token_index + len(law_section.strip().split()) # آخرین توکنی که اخیرا به عنوان قانون اضافه شده را باید برگردانیم # زیرا متناظر با این توکن اضافه شده، عنوان قانونی پیدا نشده law_section = remove_latest_added_token(law_section) matched_law_list.append({ "found_law_list": sorted_found_law_list, "law_id" : found_law['id'], "start_token_index": start_token_index, "end_token_index" : end_token_index, "law_captions" : found_law['caption'], "matched_string": law_section, "original_string": law_token, "multi_flag": True }) continue else: if len(found_law_list_2) == 1: found_law = [] found_law.append(found_law_list_2.pop()) # = found_law_list_2.pop() end_token_index = start_token_index + len(law_section.strip().split()) matched_law_list.append({ "law_id" : found_law[0]['id'], "start_token_index": start_token_index, "end_token_index" : end_token_index, "found_law_list": found_law, "law_captions" : found_law[0]['caption'], "matched_string": law_section, "original_string": law_token, "multi_flag": False }) # اگر در جستجوی عنوان قانون، به یک مورد منحصر به فرد رسیده بودیم، فقط همین یک عنوان را ذخیره کند continue # اگر تعداد توکن های متنی که احتمالا عنوان یک قانون است، دوتا بود، # از حلقه خارج می شویم و به سراغ بررسی عنوان قانون بعدی می رویم if len(law_token) < 3: continue law_section = law_token[0] + ' ' + law_token[1] + ' ' + law_token[2] for value in found_law_list_2: id = value['id'] current_caption = value['caption'] current_approve_date = value['approve_date'] rate = fuzz.token_set_ratio(current_caption,law_section) # if current_caption.__contains__(law_section): if rate == 100: # found_law_list_3.append(current_caption + '#' + str(id) + '#' +current_approve_date) found_law_list_3.append({"id": id ,"caption": current_caption, "approve_date":current_approve_date}) if len(found_law_list_3) == 0: if len(found_law_list_2) > 1 and len(found_law_list_2) < 6: # به دقت کنترل شود # مرتب سازی بر اساس قدیم به جدیدترین شناسه sorted_found_law_list = sorted(found_law_list_2, key=lambda x: x['approve_date']) found_law = sorted_found_law_list.pop() end_token_index = start_token_index + len(law_section.strip().split()) # آخرین توکنی که اخیرا به عنوان قانون اضافه شده را باید برگردانیم # زیرا متناظر با این توکن اضافه شده، عنوان قانونی پیدا نشده law_section = remove_latest_added_token(law_section) matched_law_list.append({ "found_law_list": sorted_found_law_list, "law_id" : found_law['id'], "start_token_index": start_token_index, "end_token_index" : end_token_index, "law_captions" : found_law['caption'], "matched_string": law_section, "original_string": law_token, "multi_flag": True }) continue else: if len(found_law_list_3) == 1: found_law = [] found_law.append(found_law_list_3.pop()) end_token_index = start_token_index + len(law_section.strip().split()) matched_law_list.append({ "law_id" : found_law[0]['id'], "start_token_index": start_token_index, "end_token_index" : end_token_index, "found_law_list": found_law, "law_captions" : found_law[0]['caption'], "matched_string": law_section, "original_string": law_token, "multi_flag": False }) continue # اگر تعداد توکن های متنی که احتمالا عنوان یک قانون است، سه تا بود، # از حلقه خارج می شویم و به سراغ بررسی عنوان قانون بعدی می رویم if len(law_token) < 4: continue law_section = law_token[0] + ' ' + law_token[1] + ' ' + law_token[2] + ' ' + law_token[3] for value in found_law_list_3: id = value['id'] current_caption = value['caption'] current_approve_date = value['approve_date'] rate = fuzz.token_set_ratio(current_caption,law_section) # if current_caption.__contains__(law_section): if rate == 100: # found_law_list_4.append(current_caption + '#' + str(id) + '#' +current_approve_date) found_law_list_4.append({"id": id ,"caption": current_caption, "approve_date":current_approve_date}) if len(found_law_list_4) == 0: # اگر در مرحله قبل بیش از یک مورد پیدا کرده اما در این مرحله تعداد موارد مشابه به صفر رسیده if len(found_law_list_3) > 1 and len(found_law_list_3) < 6: # به دقت کنترل شود # مرتب سازی بر اساس قدیم به جدیدترین شناسه sorted_found_law_list = sorted(found_law_list_3, key=lambda x: x['approve_date']) found_law = sorted_found_law_list.pop() end_token_index = start_token_index + len(law_section.strip().split()) # آخرین توکنی که اخیرا به عنوان قانون اضافه شده را باید برگردانیم # زیرا متناظر با این توکن اضافه شده، عنوان قانونی پیدا نشده law_section = remove_latest_added_token(law_section) matched_law_list.append({ "found_law_list": sorted_found_law_list, "law_id" : found_law['id'], "start_token_index": start_token_index, "end_token_index" : end_token_index, "law_captions" : found_law['caption'], "matched_string": law_section, "original_string": law_token, "multi_flag": True }) continue else: if len(found_law_list_4) == 1: found_law = [] found_law.append(found_law_list_4.pop()) end_token_index = start_token_index + len(law_section.strip().split()) matched_law_list.append({ "law_id" : found_law[0]['id'], "start_token_index": start_token_index, "end_token_index" : end_token_index, "found_law_list": found_law, "law_captions" : found_law[0]['caption'], "matched_string": law_section, "original_string": law_token, "multi_flag": False }) continue # اگر تعداد توکن های متنی که احتمالا عنوان یک قانون است، چهارتا بود، # از حلقه خارج می شویم و به سراغ بررسی عنوان قانون بعدی می رویم if len(law_token) < 5: continue law_section = law_token[0] + ' ' + law_token[1] + ' ' + law_token[2] + ' ' + law_token[3] + ' ' + law_token[4] for value in found_law_list_4: id = value['id'] current_caption = value['caption'] current_approve_date = value['approve_date'] rate = fuzz.token_set_ratio(current_caption,law_section) # if current_caption.__contains__(law_section): if rate == 100: # found_law_list_5.append(current_caption + '#' + str(id) + '#' +current_approve_date) found_law_list_5.append({"id": id ,"caption": current_caption, "approve_date":current_approve_date}) if len(found_law_list_5) == 0: # اگر در مرحله قبل بیش از یک مورد پیدا کرده اما در این مرحله تعداد موارد مشابه به صفر رسیده if len(found_law_list_4) > 1 and len(found_law_list_4) < 6: # به دقت کنترل شود # مرتب سازی بر اساس قدیم به جدیدترین شناسه sorted_found_law_list = sorted(found_law_list_4, key=lambda x: x['approve_date']) found_law = sorted_found_law_list.pop() end_token_index = start_token_index + len(law_section.strip().split()) # آخرین توکنی که اخیرا به عنوان قانون اضافه شده را باید برگردانیم # زیرا متناظر با این توکن اضافه شده، عنوان قانونی پیدا نشده law_section = remove_latest_added_token(law_section) matched_law_list.append({ "found_law_list": sorted_found_law_list, "law_id" : found_law['id'], "start_token_index": start_token_index, "end_token_index" : end_token_index, "law_captions" : found_law['caption'], "matched_string": law_section, "original_string": law_token, "multi_flag": True }) continue else: if len(found_law_list_5) == 1: found_law = [] found_law.append(found_law_list_5.pop()) end_token_index = start_token_index + len(law_section.strip().split()) matched_law_list.append({ "law_id" : found_law[0]['id'], "start_token_index": start_token_index, "end_token_index" : end_token_index, "found_law_list": found_law, "law_captions" : found_law[0]['caption'], "matched_string": law_section, "original_string": law_token, "multi_flag": False }) continue # اگر تعداد توکن های متنی که احتمالا عنوان یک قانون است، پنج تا بود، # از حلقه خارج می شویم و به سراغ بررسی عنوان قانون بعدی می رویم if len(law_token) < 6: continue law_section = law_token[0] + ' ' + law_token[1] + ' ' + law_token[2] + ' ' + law_token[3] + \ ' ' + law_token[4] + ' ' + law_token[5] for value in found_law_list_5: id = value['id'] current_caption = value['caption'] current_approve_date = value['approve_date'] rate = fuzz.token_set_ratio(current_caption,law_section) # if current_caption.__contains__(law_section): if rate == 100: # found_law_klist_6.append(current_caption + '#' + str(id) + '#' +current_approve_date) found_law_list_6.append({"id": id ,"caption": current_caption, "approve_date":current_approve_date}) if len(found_law_list_6) == 0: # اگر در مرحله قبل بیش از یک مورد پیدا کرده اما در این مرحله تعداد موارد مشابه به صفر رسیده if len(found_law_list_5) > 1 and len(found_law_list_5) < 6: # به دقت کنترل شود # مرتب سازی بر اساس قدیم به جدیدترین شناسه sorted_found_law_list = sorted(found_law_list_5, key=lambda x: x['approve_date']) found_law = sorted_found_law_list.pop() end_token_index = start_token_index + len(law_section.strip().split()) # آخرین توکنی که اخیرا به عنوان قانون اضافه شده را باید برگردانیم # زیرا متناظر با این توکن اضافه شده، عنوان قانونی پیدا نشده law_section = remove_latest_added_token(law_section) matched_law_list.append({ "found_law_list": sorted_found_law_list, "law_id" : found_law['id'], "start_token_index": start_token_index, "end_token_index" : end_token_index, "law_captions" : found_law['caption'], "matched_string": law_section, "original_string": law_token, "multi_flag": True }) continue else: if len(found_law_list_6) == 1: found_law = [] found_law.append(found_law_list_6.pop()) end_token_index = start_token_index + len(law_section.strip().split()) matched_law_list.append({ "law_id" : found_law[0]['id'], "start_token_index": start_token_index, "end_token_index" : end_token_index, "found_law_list": found_law, "law_captions" : found_law[0]['caption'], "matched_string": law_section, "original_string": law_token, "multi_flag": False }) continue # اگر تعداد توکن های متنی که احتمالا عنوان یک قانون است، شش تا بود، # از حلقه خارج می شویم و به سراغ بررسی عنوان قانون بعدی می رویم if len(law_token) < 7: continue law_section = law_token[0] + ' ' + law_token[1] + ' ' + law_token[2] + ' ' + law_token[3] + \ ' ' + law_token[4] + ' ' + law_token[5]+ ' ' + law_token[6] for value in found_law_list_6: id = value['id'] current_caption = value['caption'] current_approve_date = value['approve_date'] rate = fuzz.token_set_ratio(current_caption,law_section) # if current_caption.__contains__(law_section): if rate == 100: # found_law_list_7.append(current_caption + '#' + str(id) + '#' +current_approve_date) found_law_list_7.append({"id": id ,"caption": current_caption, "approve_date":current_approve_date}) if len(found_law_list_7) == 0: # اگر در مرحله قبل بیش از یک مورد پیدا کرده اما در این مرحله تعداد موارد مشابه به صفر رسیده if len(found_law_list_6) > 1 and len(found_law_list_6) < 6: # به دقت کنترل شود # مرتب سازی بر اساس قدیم به جدیدترین شناسه sorted_found_law_list = sorted(found_law_list_6, key=lambda x: x['approve_date']) found_law = sorted_found_law_list.pop() end_token_index = start_token_index + len(law_section.strip().split()) # آخرین توکنی که اخیرا به عنوان قانون اضافه شده را باید برگردانیم # زیرا متناظر با این توکن اضافه شده، عنوان قانونی پیدا نشده law_section = remove_latest_added_token(law_section) matched_law_list.append({ "found_law_list": sorted_found_law_list, "law_id" : found_law['id'], "start_token_index": start_token_index, "end_token_index" : end_token_index, "law_captions" : found_law['caption'], "matched_string": law_section, "original_string": law_token, "multi_flag": True }) continue else: if len(found_law_list_7) == 1: found_law = [] found_law.append(found_law_list_7.pop()) end_token_index = start_token_index + len(law_section.strip().split()) matched_law_list.append({ "law_id" : found_law[0]['id'], "start_token_index": start_token_index, "end_token_index" : end_token_index, "found_law_list": found_law, "law_captions" : found_law[0]['caption'], "matched_string": law_section, "original_string": law_token, "multi_flag": False }) continue # اگر تعداد توکن های متنی که احتمالا عنوان یک قانون است، هفت تا بود، # از حلقه خارج می شویم و به سراغ بررسی عنوان قانون بعدی می رویم if len(law_token) < 8: continue law_section = law_token[0] + ' ' + law_token[1] + ' ' + law_token[2] + ' ' + law_token[3] + \ ' ' + law_token[4] + ' ' + law_token[5]+ ' ' + law_token[6]+ ' ' + law_token[7] for value in found_law_list_7: id = value['id'] current_caption = value['caption'] current_approve_date = value['approve_date'] rate = fuzz.token_set_ratio(current_caption,law_section) # if current_caption.__contains__(law_section): if rate == 100: # found_law_list_8.append(current_caption + '#' + str(id) + '#' +current_approve_date) found_law_list_8.append({"id": id ,"caption": current_caption, "approve_date":current_approve_date}) if len(found_law_list_8) == 0: # اگر در مرحله قبل بیش از یک مورد پیدا کرده اما در این مرحله تعداد موارد مشابه به صفر رسیده if len(found_law_list_7) > 1 and len(found_law_list_7) < 6: # به دقت کنترل شود # مرتب سازی بر اساس قدیم به جدیدترین شناسه sorted_found_law_list = sorted(found_law_list_7, key=lambda x: x['approve_date']) found_law = sorted_found_law_list.pop() end_token_index = start_token_index + len(law_section.strip().split()) # آخرین توکنی که اخیرا به عنوان قانون اضافه شده را باید برگردانیم # زیرا متناظر با این توکن اضافه شده، عنوان قانونی پیدا نشده law_section = remove_latest_added_token(law_section) matched_law_list.append({ "found_law_list": sorted_found_law_list, "law_id" : found_law['id'], "start_token_index": start_token_index, "end_token_index" : end_token_index, "law_captions" : found_law['caption'], "matched_string": law_section, "original_string": law_token, "multi_flag": True }) continue else: if len(found_law_list_8) == 1: found_law = [] found_law.append(found_law_list_8.pop()) end_token_index = start_token_index + len(law_section.strip().split()) matched_law_list.append({ "law_id" : found_law[0]['id'], "start_token_index": start_token_index, "end_token_index" : end_token_index, "found_law_list": found_law, "law_captions" : found_law[0]['caption'], "matched_string": law_section, "original_string": law_token, "multi_flag": False }) continue # اگر تعداد توکن های متنی که احتمالا عنوان یک قانون است، هشت تا بود، # از حلقه خارج می شویم و به سراغ بررسی عنوان قانون بعدی می رویم if len(law_token) < 9: continue law_section = law_token[0] + ' ' + law_token[1] + ' ' + law_token[2] + ' ' + law_token[3] + \ ' ' + law_token[4] + ' ' + law_token[5]+ ' ' + law_token[6]+ ' ' + law_token[7]+ ' ' + law_token[8] for value in found_law_list_8: id = value['id'] current_caption = value['caption'] current_approve_date = value['approve_date'] rate = fuzz.token_set_ratio(current_caption,law_section) # if current_caption.__contains__(law_section): if rate == 100: # found_law_list_9.append(current_caption + '#' + str(id) + '#' +current_approve_date) found_law_list_9.append({"id": id ,"caption": current_caption, "approve_date":current_approve_date}) if len(found_law_list_9) == 0: # اگر در مرحله قبل بیش از یک مورد پیدا کرده اما در این مرحله تعداد موارد مشابه به صفر رسیده if len(found_law_list_8) > 1 and len(found_law_list_8) < 6: # به دقت کنترل شود # مرتب سازی بر اساس قدیم به جدیدترین شناسه sorted_found_law_list = sorted(found_law_list_8, key=lambda x: x['approve_date']) found_law = sorted_found_law_list.pop() end_token_index = start_token_index + len(law_section.strip().split()) # آخرین توکنی که اخیرا به عنوان قانون اضافه شده را باید برگردانیم # زیرا متناظر با این توکن اضافه شده، عنوان قانونی پیدا نشده law_section = remove_latest_added_token(law_section) matched_law_list.append({ "found_law_list": sorted_found_law_list, "law_id" : found_law['id'], "start_token_index": start_token_index, "end_token_index" : end_token_index, "law_captions" : found_law['caption'], "matched_string": law_section, "original_string": law_token, "multi_flag": True }) continue else: if len(found_law_list_9) == 1: sorted_found_law_list = sorted(found_law_list_9, key=lambda x: x['approve_date']) found_law = [] found_law.append(found_law_list_9.pop()) end_token_index = start_token_index + len(law_section.strip().split()) matched_law_list.append({ "law_id" : found_law[0]['id'], "start_token_index": start_token_index, "end_token_index" : end_token_index, "found_law_list": found_law, "law_captions" : found_law[0]['caption'], "matched_string": law_section, "original_string": law_token, "multi_flag": False }) elif len(found_law_list_9) > 1 and len(found_law_list_9) < 6: sorted_found_law_list = sorted(found_law_list_8, key=lambda x: x['approve_date'] ) found_law = sorted_found_law_list.pop() end_token_index = start_token_index + len(law_section.strip().split()) matched_law_list.append({ "law_id" : found_law['id'], "start_token_index": start_token_index, "end_token_index" : end_token_index, "found_law_list": found_law_list_9, "law_captions" : found_law['caption'], "matched_string": law_section, "original_string": law_token, "multi_flag": True }) if matched_law_list: for law_item in matched_law_list: temp_list = [] found_list = law_item['found_law_list'] for item in found_list: temp_list.append(item['caption'] + '#' + str(item['id']) + '#' + item['approve_date']) law_item['found_law_list'] = temp_list return matched_law_list, law_token_list def law_title_search(content,law_dict): # section_dict = read_section_table() #law_dict = read_law_table() #write_to_json(law_dict,'law_title.json') # law_dict = read_from_json('law_title.json') # i = 0 # probable = 0 # foundlist = 0 # found_law = 0 final_found_law = [] # for id, value in section_dict.items(): final_found_law, law_token_list = law_recognizer(content, law_dict) # if(len(law_token_list))>0: # probable += len(law_token_list) # for ref_value in matched_law_list: # foundlist += 1 # final_found_law.append({ # "law_id" : ref_value['law_id'],# شناسه قانون # "index_start" : int(ref_value['start_token_index']), # "index_end" : int(ref_value['end_token_index']), # "text" : ref_value['matched_string'],# توکن هایی که متناظر آنها در عناوین قانون ها وجود داشته # "text_tokens" : ref_value['original_string'],# ده توکنی که احتمالا عنوان یک قانون باشد # "result" : ref_value['found_law_list'],# لیست عناوین یافت شده # "type" : "law_title", # "ref_link" : '' # }) # for value in matched_law_list: # if value['multi_flag']: # foundlist += 1 # final_found_law.append( { # "law_id" : value['law_id'], # "start_token_index": value['start_token_index'], # "end_token_index" : value['end_token_index'], # "multi_flag" : value['multi_flag'], # "found_law_list" : value["found_law_list"], # "law_caption" : value['law_captions'], # "matched_string" : value["matched_string"], # "original_string" : value["original_string"] # }) # if not value['multi_flag']: # found_law += 1 # final_found_law.append({ # "law_id" : value['law_id'], # "start_token_index": value['start_token_index'], # "end_token_index" : value['end_token_index'], # "multi_flag" : value['multi_flag'], # "found_law_list" : value["found_law_list"], # "law_caption" : value['law_captions'], # "matched_string" : value["matched_string"], # "original_string" : value["original_string"] # }) # print(i+1) # i+=1 # print("************ Result ************") # print("probable: " + str(probable)) # print("found_law: " + str(found_law)+ " - " + str(int((found_law/probable)*100)) + " %") # print("found_list: " + str(foundlist) + " - " + str(int((foundlist/probable)*100)) + " %") return final_found_law def write_to_json(dict,file_name): data = [] for key,value in dict.items(): date_obj = value["approve_date"] year = date_obj.persian_year month = date_obj.persian_month day = date_obj.persian_day aprove_date = f'{year}-{month}-{day}' data.append({ 'id' : value["id"], 'caption' : value["caption"], 'approve_date': aprove_date }) # تبدیل دیکشنری به فرمت JSON json_data = json.dumps(data, indent=2, ensure_ascii=False) # ذخیره فایل with open(file_name, 'w', encoding='utf-8') as file: file.write(json_data) def read_from_json(file_name): data_dict = [] path = '' # خواندن اطلاعات از فایل JSON try: with open(path + file_name, 'r', encoding='utf-8') as file: loaded_data = json.load(file) except Exception as err: err = err path = os.getcwd() path = path + '/repairQanon/' with open(path + file_name, 'r', encoding='utf-8') as file: loaded_data = json.load(file) # نمایش اطلاعات خوانده شده for item in loaded_data: data_dict.append(item) return data_dict def remove_latest_added_token(text): temp = text.strip().split(' ') temp.pop() text = '' for token in temp: text = text + ' ' + token return text.strip()