Spaces:
Sleeping
Sleeping
File size: 2,759 Bytes
b2e9550 8b7b048 b2e9550 8b7b048 b2e9550 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 | """Structured abstract section detection and conservative sentence splitting."""
from __future__ import annotations
import re
from dataclasses import dataclass
@dataclass(frozen=True)
class AbstractSentence:
text: str
source_location: str
ordinal: int
_HEADING_TO_LOCATION = {
"BACKGROUND": "abstract_background",
"BACKGROUND AND OBJECTIVE": "abstract_background",
"OBJECTIVE": "abstract_background",
"OBJECTIVES": "abstract_background",
"AIM": "abstract_background",
"AIMS": "abstract_background",
"INTRODUCTION": "abstract_background",
"METHOD": "abstract_methods",
"METHODS": "abstract_methods",
"MATERIAL AND METHODS": "abstract_methods",
"MATERIALS AND METHODS": "abstract_methods",
"DESIGN": "abstract_methods",
"PARTICIPANTS": "abstract_methods",
"RESULT": "abstract_results",
"RESULTS": "abstract_results",
"FINDINGS": "abstract_results",
"CONCLUSION": "abstract_conclusion",
"CONCLUSIONS": "abstract_conclusion",
"INTERPRETATION": "abstract_conclusion",
}
# INLINE_STRUCTURED_ABSTRACT_HEADINGS_V423
_HEADING_RE = re.compile(
r"(?im)(?<!\S)(BACKGROUND(?: AND OBJECTIVE)?|OBJECTIVES?|AIMS?|INTRODUCTION|METHODS?|MATERIALS? AND METHODS|DESIGN|PARTICIPANTS|RESULTS?|FINDINGS|CONCLUSIONS?|INTERPRETATION)\s*[:.]\s*"
)
_SENTENCE_RE = re.compile(r"(?<=[.!?])\s+(?=(?:[A-Z0-9]|\())")
def _clean(text: str) -> str:
return re.sub(r"\s+", " ", text).strip()
def split_sentences(text: str) -> list[str]:
cleaned = _clean(text)
if not cleaned:
return []
parts = [_clean(part) for part in _SENTENCE_RE.split(cleaned)]
return [part for part in parts if len(part) >= 10]
def section_abstract(abstract: str) -> list[AbstractSentence]:
matches = list(_HEADING_RE.finditer(abstract))
out: list[AbstractSentence] = []
ordinal = 0
if not matches:
for sentence in split_sentences(abstract):
ordinal += 1
out.append(AbstractSentence(sentence, "abstract_unspecified", ordinal))
return out
prefix = abstract[: matches[0].start()].strip()
for sentence in split_sentences(prefix):
ordinal += 1
out.append(AbstractSentence(sentence, "abstract_unspecified", ordinal))
for index, match in enumerate(matches):
heading = match.group(1).upper().strip()
start = match.end()
end = matches[index + 1].start() if index + 1 < len(matches) else len(abstract)
section_text = abstract[start:end]
location = _HEADING_TO_LOCATION.get(heading, "abstract_unspecified")
for sentence in split_sentences(section_text):
ordinal += 1
out.append(AbstractSentence(sentence, location, ordinal))
return out
|