""" Pattern and symbol replacement helper functions. This module provides utilities for applying symbol mappings and regex patterns to text, used throughout the conversion pipeline. """ import re import logging logger = logging.getLogger(__name__) def apply_symbol_replacements(text: str, mapping: dict) -> str: """Apply simple symbol replacements from a mapping dictionary. Args: text: Input text mapping: Dictionary of {symbol: replacement} Returns: Text with all symbols replaced Example: >>> mapping = {'α': '\\\\alpha', 'β': '\\\\beta'} >>> apply_symbol_replacements('α + β', mapping) '\\\\alpha + \\\\beta' """ for symbol, replacement in mapping.items(): text = text.replace(symbol, replacement) return text def apply_pattern_replacements(text: str, patterns: list, verbose: bool = False) -> str: """Apply regex pattern replacements from a list of (pattern, replacement, description) tuples. Args: text: Input text patterns: List of (pattern, replacement, description) tuples verbose: If True, log each replacement Returns: Text with all patterns applied Example: >>> patterns = [(r' {3,}', ' ', 'Reduce multiple spaces')] >>> apply_pattern_replacements('a b', patterns) 'a b' """ for pattern, replacement, description in patterns: if verbose: count = len(re.findall(pattern, text)) if count > 0: logger.debug(f"Applying: {description} ({count} matches)") text = re.sub(pattern, replacement, text) return text def apply_unicode_symbol_mapping( text: str, unicode_to_latex: dict, additional_replacements: dict = None, subscript_context: bool = False ) -> str: """Apply Unicode to LaTeX symbol mapping. Args: text: Input text containing Unicode symbols unicode_to_latex: Main Unicode to LaTeX mapping dictionary additional_replacements: Optional additional symbol replacements subscript_context: If True, use subscript-specific mappings (with spaces) Returns: Text with Unicode symbols converted to LaTeX Example: >>> mapping = {'α': '\\\\alpha', '→': '\\\\to'} >>> apply_unicode_symbol_mapping('α → β', mapping, {}) '\\\\alpha \\\\to β' """ # First apply standard UNICODE_TO_LATEX mapping for symbol, latex in unicode_to_latex.items(): text = text.replace(symbol, latex) # In subscript context, apply additional replacements with proper spacing if subscript_context and additional_replacements: for symbol, latex in additional_replacements.items(): text = text.replace(symbol, latex) return text def is_default_color(color: str) -> bool: """Check if a color value represents the default (black) color. Args: color: Color value in various formats (hex, name, rgb) Returns: True if the color is black/default, False otherwise Examples: >>> is_default_color('#000000') True >>> is_default_color('#000') True >>> is_default_color('black') True >>> is_default_color('rgb(0, 0, 0)') True >>> is_default_color('#FF0000') False >>> is_default_color('red') False """ if not color: return False # Normalize the color string color_lower = color.lower().strip() # Check for common black color representations black_colors = { '#000000', # Full hex '#000', # Short hex 'black', # Named color 'rgb(0,0,0)', # RGB without spaces 'rgb(0, 0, 0)', # RGB with spaces 'rgba(0,0,0,1)', # RGBA without spaces 'rgba(0, 0, 0, 1)', # RGBA with spaces } # Remove all whitespace for comparison color_normalized = ''.join(color_lower.split()) return color_normalized in {c.replace(' ', '') for c in black_colors}