import re class BBCodeParser: def __init__(self): # On défini ici les balises BBcode et leur équivalent en html self.bbcode_patterns = { r'\[b\](.*?)\[/b\]': r'\1', r'\[i\](.*?)\[/i\]': r'\1', r'\[u\](.*?)\[/u\]': r'\1', r'\[s\](.*?)\[/s\]': r'\1', r'\[url=(.*?)\](.*?)\[/url\]': r'\2', r'\[url\](.*?)\[/url\]': r'\1', r'\[url=(.*?)(?:\s+class=(.*?))?\](.*?)\[/url\]': lambda m: f'{{m.group(3)}}', r'\[url\](?:\s+class=(.*?))?\](.*?)\[/url\]': lambda m: f'{{m.group(2)}}', r'\[img alt=(.*?)\](.*?)\[/img\]': r'\1', r'\[img\](.*?)\[/img\]': r'Image insérer par un utilisateur', r'\[list\](.*?)\[/list\]': r'', r'\[\*\](.*?)': r'
  • \1
  • ', r'\[t1\](.*?)\[/t1\]': r'\1', r'\[t2\](.*?)\[/t2\]': r'\1', r'\[t3\](.*?)\[/t3\]': r'\1', r'\[citation\](.*?)\[/citation\]': r'
    \1
    ', r'\[citation=(.*?)\](.*?)\[/citation\]': r'
    \1\2
    ', r'\[quote\](.*?)\[/quote\]': r'
    \1
    ', r'\[quote=(.*?)\](.*?)\[/quote\]': r'
    \1\2
    ', r'\[color=(.*?)\](.*?)\[/color\]': r'\2', r'\[size=(.*?)\](.*?)\[/size\]': r'\2', r'\[p](.*?)\[/p\]': r'

    \1

    ', r'\[center\](.*?)\[/center\]': r'
    \1
    ', r'\[right\](.*?)\[/right\]': r'
    \1
    ', r'\[hr\]': r'
    ', r'\[block\](.*?)\[/block\]': r'
    \1
    ', r'\[block style=(.*?)\](.*?)\[/block\]': r'
    \2
    ', r'\[block class=(.*?)\](.*?)\[/block\]': r'
    \2
    ', r'\[block style=(.*?) class=(.*?)\](.*?)\[/block\]': r'
    \3
    ', r'\[code\](.*?)\[/code\]': lambda m: self._handle_code(m.group(1)), r'\[code=(.*?)\](.*?)\[/code\]': lambda m: self._handle_code(m.group(2), m.group(1)), } def _handle_code(self, content, language='none'): # Convertit les retours à la ligne en \n littéraux escaped_content = ( content .replace('&', '&') .replace('<', '<') .replace('>', '>') .replace('"', '"') .replace("'", ''') .replace('\r\n', '\n') # Normalise les retours à la ligne Windows .replace('\r', '\n') # Normalise les retours à la ligne Mac ) # Enveloppe dans pre/code sans modifier les \n return f'''
    {escaped_content}
    ''' def parse(self, text): # Protège temporairement le contenu des balises [code] code_blocks = [] def save_code(match): code_blocks.append(match.group(0)) return f'@@CODE_BLOCK_{len(code_blocks)-1}@@' text = re.sub(r'\[code(?:=.*?)?\].*?\[/code\]', save_code, text, flags=re.DOTALL) # Parse les autres BBCodes for bbcode, html in self.bbcode_patterns.items(): if callable(html): text = re.sub(bbcode, html, text, flags=re.DOTALL) else: text = re.sub(bbcode, html, text, flags=re.DOTALL) # Restaure les blocs de code for i, code_block in enumerate(code_blocks): if '=' in code_block: # code avec langage spécifié lang = re.match(r'\[code=(.*?)\]', code_block).group(1) content = re.search(r'\[code=.*?\](.*?)\[/code\]', code_block, re.DOTALL).group(1) else: # code sans langage lang = 'none' content = re.search(r'\[code\](.*?)\[/code\]', code_block, re.DOTALL).group(1) text = text.replace(f'@@CODE_BLOCK_{i}@@', self._handle_code(content, lang)) return text