add: LayoutProcessor - обработка едениц измерения (кажется все++ и реализована безопасность от CHAR_UNIT_SEPARATOR)

This commit is contained in:
2025-09-22 10:27:59 +03:00
parent fb9d7f9072
commit ddeb7c6d99

View File

@@ -71,30 +71,33 @@ class LayoutProcessor:
self._math_unit_pattern = None self._math_unit_pattern = None
if self.process_units: if self.process_units:
all_post_units = list(DEFAULT_POST_UNITS) all_post_units = list(DEFAULT_POST_UNITS)
# Добавляем кастомные единицы, если они есть
if isinstance(self.process_units, str): if isinstance(self.process_units, str):
all_post_units.extend(self.process_units.split()) all_post_units.extend(self.process_units.split())
elif isinstance(self.process_units, (list, tuple, set)): elif isinstance(self.process_units, (list, tuple, set)):
all_post_units.extend(self.process_units) all_post_units.extend(self.process_units)
# Общий паттерн для всех остальных единиц # Единая проверка безопасности: удаляем все единицы, содержащие временный разделитель.
if all_post_units: safe_units = [unit for unit in all_post_units if CHAR_UNIT_SEPARATOR not in unit]
sorted_units = sorted(all_post_units, key=len, reverse=True) if len(safe_units) != len(all_post_units):
# Создаем "чистый" паттерн без точек для универсальности logger.warning(f"One or more units contained the reserved separator ('{CHAR_UNIT_SEPARATOR}') and were ignored.")
units_pattern_part_clean = '|'.join(map(regex.escape, [u.replace('.', '') for u in sorted_units]))
# Создаем паттерн, который включает единицы с точками, для простых замен
units_pattern_part_full = '|'.join(map(regex.escape, sorted_units))
if units_pattern_part_full: # Создаем паттерны только из безопасных единиц
# Простые единицы: число + единица if safe_units:
self._post_units_pattern = regex.compile(rf'({self._NUMBER_PATTERN})\s+({units_pattern_part_full})(?!\w)') sorted_units = sorted(safe_units, key=len, reverse=True)
# Паттерн для составных единиц: ищет пару "единица." + "единица", разделенную пробелами (или без них). units_pattern_part_full = '|'.join(map(regex.escape, sorted_units))
# Обязательное наличие точки `\.` после первой единицы делает цикл обработки безопасным. units_pattern_part_clean = '|'.join(map(regex.escape, [u.replace('.', '') for u in sorted_units]))
# Используем "чистый" паттерн, чтобы правило работало независимо от того, как определена единица ('в' или 'в.')
self._complex_unit_pattern = regex.compile(r'\b(' + units_pattern_part_clean + r')\.(\s*)(' + units_pattern_part_clean + r')(?!\w)') # Простые единицы: число + единица
# Паттерн для математических операций между единицами self._post_units_pattern = regex.compile(rf'({self._NUMBER_PATTERN})\s+({units_pattern_part_full})(?!\w)')
math_ops_pattern = '|'.join(map(regex.escape, UNIT_MATH_OPERATORS)) # Составные единицы: ищет пару "единица." + "единица"
self._math_unit_pattern = regex.compile( self._complex_unit_pattern = regex.compile(r'\b(' + units_pattern_part_clean + r')\.(\s*)('
r'\b(' + units_pattern_part_clean + r')\s*(' + math_ops_pattern + r')\s*(' + units_pattern_part_clean + r')(?!\w)') + units_pattern_part_clean + r')(?!\w)')
# Математические операции между единицами
math_ops_pattern = '|'.join(map(regex.escape, UNIT_MATH_OPERATORS))
self._math_unit_pattern = regex.compile(
r'\b(' + units_pattern_part_clean + r')\s*(' + math_ops_pattern + r')\s*('
+ units_pattern_part_clean + r')(?!\w)')
# Паттерн для пред-позиционных единиц # Паттерн для пред-позиционных единиц
self._pre_units_pattern = regex.compile( self._pre_units_pattern = regex.compile(