Legora / db /parsers /consitution /reference_extractor.py
sai-Rohan's picture
combined results of all parsers and made a single pipeline
dbabef2
Raw
History Blame Contribute Delete
8.2 kB
from __future__ import annotations
import re
from typing import List
from db.parsers.consitution.legal_models import Reference
class ReferenceExtractor:
"""
Extract legal references from Constitution text.
Supports:
Article 21
Article 21A
Articles 14, 19 and 21
Part III
Chapter IV
Seventh Schedule
Clause (2)
Sub-clause (a)
"""
# =====================================================
# ARTICLE REFERENCES
# =====================================================
ARTICLE_RE = re.compile(
r"""
Articles?
\s+
(
[\dA-Z,\-\sandto]+
)
""",
re.IGNORECASE
| re.VERBOSE
)
# =====================================================
# PART REFERENCES
# =====================================================
PART_RE = re.compile(
r"""
Part
\s+
([IVXLCDM]+)
""",
re.IGNORECASE
| re.VERBOSE
)
# =====================================================
# CHAPTER REFERENCES
# =====================================================
CHAPTER_RE = re.compile(
r"""
Chapter
\s+
([IVXLCDM]+)
""",
re.IGNORECASE
| re.VERBOSE
)
# =====================================================
# SCHEDULE REFERENCES
# =====================================================
SCHEDULE_RE = re.compile(
r"""
(
First
|Second
|Third
|Fourth
|Fifth
|Sixth
|Seventh
|Eighth
|Ninth
|Tenth
|Eleventh
|Twelfth
)
\s+
Schedule
""",
re.IGNORECASE
| re.VERBOSE
)
# =====================================================
# CLAUSE REFERENCES
# =====================================================
CLAUSE_RE = re.compile(
r"""
Clause
\s*
\(
(\d+[A-Z]?)
\)
""",
re.IGNORECASE
| re.VERBOSE
)
# =====================================================
# SUBCLAUSE REFERENCES
# =====================================================
SUBCLAUSE_RE = re.compile(
r"""
Sub[\-\s]?
Clause
\s*
\(
([a-z])
\)
""",
re.IGNORECASE
| re.VERBOSE
)
# =====================================================
# ARTICLE PARSER
# =====================================================
def extract_articles(
self,
text: str
) -> List[Reference]:
refs = []
matches = (
self.ARTICLE_RE.finditer(
text
)
)
for match in matches:
raw = match.group(1)
articles = re.findall(
r"\d+[A-Z]{0,3}",
raw
)
for article_no in articles:
refs.append(
Reference(
reference_type="ARTICLE",
reference_value=article_no,
text=match.group(0)
)
)
return refs
# =====================================================
# PARTS
# =====================================================
def extract_parts(
self,
text: str
) -> List[Reference]:
refs = []
for match in self.PART_RE.finditer(
text
):
refs.append(
Reference(
reference_type="PART",
reference_value=match.group(1),
text=match.group(0)
)
)
return refs
# =====================================================
# CHAPTERS
# =====================================================
def extract_chapters(
self,
text: str
) -> List[Reference]:
refs = []
for match in self.CHAPTER_RE.finditer(
text
):
refs.append(
Reference(
reference_type="CHAPTER",
reference_value=match.group(1),
text=match.group(0)
)
)
return refs
# =====================================================
# SCHEDULES
# =====================================================
def extract_schedules(
self,
text: str
) -> List[Reference]:
refs = []
for match in self.SCHEDULE_RE.finditer(
text
):
refs.append(
Reference(
reference_type="SCHEDULE",
reference_value=match.group(1).upper(),
text=match.group(0)
)
)
return refs
# =====================================================
# CLAUSES
# =====================================================
def extract_clauses(
self,
text: str
) -> List[Reference]:
refs = []
for match in self.CLAUSE_RE.finditer(
text
):
refs.append(
Reference(
reference_type="CLAUSE",
reference_value=match.group(1),
text=match.group(0)
)
)
return refs
# =====================================================
# SUB CLAUSES
# =====================================================
def extract_subclauses(
self,
text: str
) -> List[Reference]:
refs = []
for match in self.SUBCLAUSE_RE.finditer(
text
):
refs.append(
Reference(
reference_type="SUBCLAUSE",
reference_value=match.group(1),
text=match.group(0)
)
)
return refs
# =====================================================
# MAIN EXTRACTION
# =====================================================
def extract(
self,
text: str
) -> List[Reference]:
refs = []
refs.extend(
self.extract_articles(
text
)
)
refs.extend(
self.extract_parts(
text
)
)
refs.extend(
self.extract_chapters(
text
)
)
refs.extend(
self.extract_schedules(
text
)
)
refs.extend(
self.extract_clauses(
text
)
)
refs.extend(
self.extract_subclauses(
text
)
)
return refs
# =====================================================
# REMOVE DUPLICATES
# =====================================================
def deduplicate(
self,
refs: List[Reference]
) -> List[Reference]:
seen = set()
unique = []
for ref in refs:
key = (
ref.reference_type,
ref.reference_value
)
if key in seen:
continue
seen.add(key)
unique.append(ref)
return unique
# =========================================================
# EXAMPLE
# =========================================================
if __name__ == "__main__":
sample = """
Subject to Article 368.
Articles 14, 19 and 21.
Under Part III.
See Chapter IV.
Refer Seventh Schedule.
Clause (2).
Sub-Clause (a).
"""
extractor = ReferenceExtractor()
refs = extractor.extract(
sample
)
refs = extractor.deduplicate(
refs
)
for ref in refs:
print(
ref.reference_type,
ref.reference_value
)