Parse plain text format content
(self, text_content: str)
| 80 | raise ParseError(f"BibTeX parsing failed: {str(e)}") |
| 81 | |
| 82 | def _parse_text(self, text_content: str) -> List[RawEntry]: |
| 83 | """Parse plain text format content""" |
| 84 | entries = [] |
| 85 | |
| 86 | # Split text blocks using double newlines |
| 87 | text_blocks = text_content.split('\n\n') |
| 88 | |
| 89 | for i, block in enumerate(text_blocks): |
| 90 | block = block.strip() |
| 91 | if not block: |
| 92 | continue |
| 93 | |
| 94 | raw_entry: RawEntry = { |
| 95 | 'id': i, |
| 96 | 'raw_text': block, |
| 97 | 'doi': None, |
| 98 | 'url': None, |
| 99 | 'query_string': None |
| 100 | } |
| 101 | |
| 102 | doi_match = re.search(r'10\.\d{4,}/[^\s,}]+', block) |
| 103 | if doi_match: |
| 104 | raw_entry['doi'] = doi_match.group().rstrip('.,;:)]') |
| 105 | else: |
| 106 | # Try to find article ID patterns that might be convertible to DOI |
| 107 | # Common patterns: e0000429, PMC123456, etc. |
| 108 | article_id_match = re.search(r'\b[eE]\d{7}\b', block) # PLOS style: e0000429 |
| 109 | if article_id_match: |
| 110 | article_id = article_id_match.group() |
| 111 | # Note potential PLOS article ID but don't assume specific journal |
| 112 | # Let Cross resolve the actual DOI during identification |
| 113 | self.logger.info(f"Entry {i} found potential PLOS article ID {article_id}, will attempt resolution via CrossRef") |
| 114 | if not raw_entry['query_string']: |
| 115 | raw_entry['query_string'] = block |
| 116 | |
| 117 | url_match = re.search(r'https?://[^\s]+', block) |
| 118 | if url_match: |
| 119 | raw_entry['url'] = url_match.group() |
| 120 | |
| 121 | # If no DOI or URL found, build a concise query string from title/author/year |
| 122 | if not raw_entry['doi'] and not raw_entry['url']: |
| 123 | # Check if block is a bare PMID (7-8 digits, optionally prefixed with "PMID:") |
| 124 | if re.match(r'^(PMID:?\s*)?\d{7,8}$', block.strip(), re.IGNORECASE): |
| 125 | raw_entry['query_string'] = block.strip() |
| 126 | else: |
| 127 | lines = [ln.strip() for ln in block.splitlines() if ln.strip()] |
| 128 | title_text = lines[0] if lines else block |
| 129 | authors_text = lines[1] if len(lines) > 1 else '' |
| 130 | year_match = re.search(r'(19|20)\d{2}', block) |
| 131 | year_text = year_match.group(0) if year_match else '' |
| 132 | |
| 133 | query_parts: List[str] = [] |
| 134 | if title_text: |
| 135 | query_parts.append(title_text) |
| 136 | if authors_text: |
| 137 | query_parts.append(authors_text) |
| 138 | if year_text: |
| 139 | query_parts.append(year_text) |