|
|
| from __future__ import annotations |
|
|
| import re |
| from typing import List, Dict |
|
|
| from db.parsers.consitution.legal_models import ( |
| Schedule, |
| ScheduleParagraph |
| ) |
|
|
|
|
| class ScheduleParser: |
|
|
| """ |
| Constitution Schedule Parser |
| |
| Supports: |
| |
| FIRST SCHEDULE |
| SECOND SCHEDULE |
| THIRD SCHEDULE |
| ... |
| TWELFTH SCHEDULE |
| """ |
|
|
| |
| |
| |
|
|
| SCHEDULE_RE = re.compile( |
| r""" |
| ^ |
| ( |
| FIRST |
| |SECOND |
| |THIRD |
| |FOURTH |
| |FIFTH |
| |SIXTH |
| |SEVENTH |
| |EIGHTH |
| |NINTH |
| |TENTH |
| |ELEVENTH |
| |TWELFTH |
| ) |
| |
| \s+ |
| |
| SCHEDULE |
| \s*$ |
| """, |
| re.IGNORECASE |
| | re.MULTILINE |
| | re.VERBOSE |
| ) |
|
|
| |
| |
| |
|
|
| PARAGRAPH_RE = re.compile( |
| r"(?m)^\s*(\d+)\.\s" |
| ) |
|
|
| |
| |
| |
|
|
| def clean_text( |
| self, |
| text: str |
| ) -> str: |
|
|
| text = text.strip() |
|
|
| text = re.sub( |
| r"\s+", |
| " ", |
| text |
| ) |
|
|
| return text |
|
|
| |
| |
| |
|
|
| def extract_schedule_title( |
| self, |
| schedule_text: str |
| ) -> str: |
|
|
| lines = [ |
| line.strip() |
| for line in schedule_text.split( |
| "\n" |
| ) |
| if line.strip() |
| ] |
|
|
| if len(lines) < 2: |
| return "" |
|
|
| title_lines = [] |
|
|
| for line in lines[1:8]: |
|
|
| if re.match( |
| r"^\d+\.", |
| line |
| ): |
| break |
|
|
| title_lines.append( |
| line |
| ) |
|
|
| return self.clean_text( |
| " ".join(title_lines) |
| ) |
|
|
| |
| |
| |
|
|
| def parse_paragraphs( |
| self, |
| schedule_text: str |
| ) -> List[ScheduleParagraph]: |
|
|
| paragraphs = [] |
|
|
| matches = list( |
| self.PARAGRAPH_RE.finditer( |
| schedule_text |
| ) |
| ) |
|
|
| if not matches: |
| return paragraphs |
|
|
| for i, match in enumerate( |
| matches |
| ): |
|
|
| start = match.start() |
|
|
| end = ( |
| matches[i + 1].start() |
| if i + 1 < len(matches) |
| else len(schedule_text) |
| ) |
|
|
| para_no = match.group(1) |
|
|
| para_text = ( |
| schedule_text[start:end] |
| .strip() |
| ) |
|
|
| paragraphs.append( |
| ScheduleParagraph( |
| document="constitution", |
| paragraph_no=para_no, |
| text=para_text |
| ) |
| ) |
|
|
| return paragraphs |
|
|
| |
| |
| |
|
|
| def extract_schedules( |
| self, |
| text: str |
| ) -> List[Schedule]: |
|
|
| matches = list( |
| self.SCHEDULE_RE.finditer( |
| text |
| ) |
| ) |
|
|
| schedules = [] |
|
|
| if not matches: |
| return schedules |
|
|
| for i, match in enumerate( |
| matches |
| ): |
|
|
| start = match.start() |
|
|
| end = ( |
| matches[i + 1].start() |
| if i + 1 < len(matches) |
| else len(text) |
| ) |
|
|
| schedule_no = ( |
| match.group(1) |
| .upper() |
| ) |
|
|
| schedule_text = ( |
| text[start:end] |
| .strip() |
| ) |
|
|
| schedule_title = ( |
| self.extract_schedule_title( |
| schedule_text |
| ) |
| ) |
|
|
| schedule = Schedule( |
| document="constitution", |
| schedule_no=schedule_no, |
| schedule_title=schedule_title, |
| text=schedule_text |
| ) |
|
|
| schedule.paragraphs.extend( |
| self.parse_paragraphs( |
| schedule_text |
| ) |
| ) |
|
|
| schedules.append( |
| schedule |
| ) |
|
|
| return schedules |
|
|
| |
| |
| |
|
|
| def validate_schedules( |
| self, |
| schedules: List[Schedule] |
| ) -> List[str]: |
|
|
| errors = [] |
|
|
| seen = set() |
|
|
| for schedule in schedules: |
|
|
| if schedule.schedule_no in seen: |
|
|
| errors.append( |
| f"Duplicate Schedule " |
| f"{schedule.schedule_no}" |
| ) |
|
|
| seen.add( |
| schedule.schedule_no |
| ) |
|
|
| if not schedule.schedule_title: |
|
|
| errors.append( |
| f"Missing Title " |
| f"for Schedule " |
| f"{schedule.schedule_no}" |
| ) |
|
|
| return errors |
|
|
|
|
| |
| |
| |
|
|
| if __name__ == "__main__": |
|
|
| sample = """ |
| FIRST SCHEDULE |
| |
| THE STATES |
| |
| 1. Andhra Pradesh |
| |
| 2. Telangana |
| |
| 3. Karnataka |
| |
| SECOND SCHEDULE |
| |
| SALARIES |
| |
| 1. President |
| |
| 2. Governors |
| """ |
|
|
| parser = ScheduleParser() |
|
|
| schedules = ( |
| parser.extract_schedules( |
| sample |
| ) |
| ) |
|
|
| print( |
| f"Schedules Found: " |
| f"{len(schedules)}" |
| ) |
|
|
| for sch in schedules: |
|
|
| print() |
|
|
| print( |
| sch.schedule_no |
| ) |
|
|
| print( |
| sch.schedule_title |
| ) |
|
|
| print( |
| len( |
| sch.paragraphs |
| ) |
| ) |
|
|
| print( |
| parser.validate_schedules( |
| schedules |
| ) |
| ) |
|
|