Constrain automatic aliases and cache terminology matchers
This commit is contained in:
@@ -4,13 +4,19 @@ import json
|
||||
import re
|
||||
import copy
|
||||
from pathlib import Path
|
||||
from functools import lru_cache
|
||||
from src.common.utils import setup_logger
|
||||
|
||||
logger = setup_logger('glossary')
|
||||
COMMON_ALIASES = {'who', 'us', 'it', 'he', 'she', 'we', 'you', 'they', 'me', 'them',
|
||||
'our', 'my', 'the', 'a', 'an', 'in', 'on', 'at', 'to', 'of', 'or',
|
||||
'dad', 'father', 'mother', 'mom', 'son', 'brother', 'sister',
|
||||
'family', 'face', 'carry'}
|
||||
'family', 'face', 'carry', 'arm',
|
||||
'january', 'february', 'march', 'april', 'may', 'june', 'july',
|
||||
'august', 'september', 'october', 'november', 'december',
|
||||
'chinese', 'japanese', 'korean', 'russian', 'english', 'french',
|
||||
'german', 'british', 'american', 'indian', 'african', 'asian',
|
||||
'european', 'turkish', 'italian'}
|
||||
|
||||
|
||||
def sanitize_automatic_terms(terms, ambiguous_aliases):
|
||||
@@ -23,6 +29,11 @@ def sanitize_automatic_terms(terms, ambiguous_aliases):
|
||||
keep = []
|
||||
for alias in term.get('aliases', []):
|
||||
unsafe = alias.casefold() in COMMON_ALIASES or re.fullmatch(r'[a-z]+', alias)
|
||||
if re.fullmatch(r'[A-Za-z][A-Za-z.-]*', alias) and alias != term['source']:
|
||||
acronym = bool(re.fullmatch(r'[A-Z][A-Z.-]+', alias))
|
||||
nickname = 'nickname' in term.get('notes', '').casefold() and alias in term.get('notes', '')
|
||||
if not acronym and not nickname:
|
||||
unsafe = True
|
||||
# A surname shared implicitly by another full name is ambiguous,
|
||||
# even when the model did not explicitly propose it as an alias.
|
||||
for other in terms:
|
||||
@@ -48,13 +59,18 @@ def source_digest(entries):
|
||||
|
||||
|
||||
def matches(source, text):
|
||||
return alias_pattern(source).search(text) is not None
|
||||
|
||||
|
||||
@lru_cache(maxsize=8192)
|
||||
def alias_pattern(source):
|
||||
# Word boundaries for Latin aliases prevent Son matching Sony / grandson.
|
||||
escaped = re.escape(source)
|
||||
if source and source[0].isascii() and source[0].isalnum():
|
||||
escaped = r'(?<!\w)' + escaped
|
||||
if source and source[-1].isascii() and source[-1].isalnum():
|
||||
escaped += r'(?!\w)'
|
||||
return re.search(escaped, text, matching_flags(source)) is not None
|
||||
return re.compile(escaped, matching_flags(source))
|
||||
|
||||
|
||||
def matching_flags(alias):
|
||||
@@ -94,12 +110,7 @@ class BookGlossary:
|
||||
excluded = [m.span() for context in term.get('exclude_contexts', [])
|
||||
for m in re.finditer(re.escape(context), text, re.IGNORECASE)]
|
||||
for alias in [term['source']] + term.get('aliases', []):
|
||||
pattern = re.escape(alias)
|
||||
if alias[0].isascii() and alias[0].isalnum():
|
||||
pattern = r'(?<!\w)' + pattern
|
||||
if alias[-1].isascii() and alias[-1].isalnum():
|
||||
pattern += r'(?!\w)'
|
||||
for match in re.finditer(pattern, text, matching_flags(alias)):
|
||||
for match in alias_pattern(alias).finditer(text):
|
||||
start, end = match.span()
|
||||
if any(start < right and end > left for left, right in excluded):
|
||||
continue
|
||||
|
||||
Reference in New Issue
Block a user