Legora / db /parsers /bnss /chapter_parser.py
sai-Rohan's picture
Added bnss parser with high complexity
eaff197
Raw
History Blame Contribute Delete
5.49 kB
from __future__ import annotations
import re
from typing import List, Dict
class ChapterParser:
"""
Bharatiya Nyaya Sanhita Chapter Parser
Extracts:
CHAPTER I
PRELIMINARY
CHAPTER II
OF PUNISHMENTS
Returns:
chapter_no
chapter_title
text
start
end
"""
# =====================================================
# CHAPTER HEADER
# =====================================================
CHAPTER_RE = re.compile(
r"(?m)^CHAPTER\s+([IVXLCDM]+)\s*$"
)
# =====================================================
# CLEAN TITLE
# =====================================================
@staticmethod
def clean_title(
title: str
) -> str:
title = title.strip()
title = re.sub(
r"\s+",
" ",
title
)
title = title.strip(
"-— "
)
return title
# =====================================================
# EXTRACT CHAPTER TITLE
# =====================================================
def extract_title(
self,
text: str,
start: int
) -> str:
chunk = text[
start:start + 1000
]
lines = [
x.strip()
for x in chunk.split("\n")
if x.strip()
]
if len(lines) < 2:
return ""
for line in lines[1:10]:
# Stop if section starts
if re.match(
r"^\d+\.",
line
):
break
# Stop if another chapter
if re.match(
r"^CHAPTER\s+",
line,
re.I
):
break
# Ignore page numbers
if re.match(
r"^\d+$",
line
):
continue
if len(line) < 200:
return self.clean_title(
line
)
return ""
# =====================================================
# EXTRACT CHAPTERS
# =====================================================
def extract_chapters(
self,
text: str
) -> List[Dict]:
matches = list(
self.CHAPTER_RE.finditer(
text
)
)
if not matches:
return []
chapters = []
for i, match in enumerate(
matches
):
start = match.start()
end = (
matches[i + 1].start()
if i + 1 < len(matches)
else len(text)
)
chapter_no = (
match.group(1)
.strip()
)
chapter_title = (
self.extract_title(
text,
start
)
)
chapter_text = (
text[start:end]
.strip()
)
chapters.append(
{
"chapter_no":
chapter_no,
"chapter_title":
chapter_title,
"text":
chapter_text,
"start":
start,
"end":
end
}
)
return chapters
# =====================================================
# VALIDATION
# =====================================================
def validate_chapters(
self,
chapters: List[Dict]
) -> List[str]:
errors = []
seen = set()
for chapter in chapters:
chapter_no = (
chapter["chapter_no"]
)
if chapter_no in seen:
errors.append(
f"Duplicate Chapter "
f"{chapter_no}"
)
seen.add(
chapter_no
)
if not chapter[
"chapter_title"
]:
errors.append(
f"Missing title for "
f"Chapter {chapter_no}"
)
return errors
# =========================================================
# EXAMPLE
# =========================================================
if __name__ == "__main__":
with open(
"../../pdfs/bns.txt",
"r",
encoding="utf8"
) as f:
text = f.read()
parser = ChapterParser()
chapters = parser.extract_chapters(text)
for chapter_dict in chapters[:2]:
print("\n" + "="*100)
print("CHAPTER:", chapter_dict["chapter_no"])
print(chapter_dict["text"][:3000])
# chapters = (
# parser.extract_chapters(
# text
# )
# )
# print(
# f"Chapters Found: "
# f"{len(chapters)}\n"
# )
# for chapter in chapters:
# print(
# f"{chapter['chapter_no']} "
# f"-> "
# f"{chapter['chapter_title']}"
# )
# print()
# errors = (
# parser.validate_chapters(
# chapters
# )
# )
# print(
# f"Errors: "
# f"{len(errors)}"
# )
# for e in errors:
# print(e)