from __future__ import annotations import re SLACK_MENTION_STRIP_PATTERN = re.compile(r"<@[^>\s]+>") SLACK_CHANNEL_PATTERN = re.compile(r"<#([A-Z0-9]+)(?:\|([^>]+))?>") SLACK_URL_PATTERN = re.compile(r"<(https?://[^|>]+)(?:\|([^>]+))?>") SLACK_SUBTEAM_PATTERN = re.compile(r"]+))?>") SLACK_SPECIAL_MENTION_PATTERN = re.compile(r"]+)>") SLACK_HTML_ENTITY_PATTERN = re.compile(r"&(amp|lt|gt|quot);") _HTML_ENTITIES = {"amp": "&", "lt": "<", "gt": ">", "quot": '"'} def strip_mentions(text: str) -> str: return SLACK_MENTION_STRIP_PATTERN.sub("", text).strip() def extract_mentions(text: str) -> list[str]: return re.findall(r"<@([A-Z0-9]+)>", text) def normalize_channel_refs(text: str) -> str: def repl(m: re.Match) -> str: name = m.group(2) return f"#{name}" if name else f"#{m.group(1)}" return SLACK_CHANNEL_PATTERN.sub(repl, text) def normalize_urls(text: str) -> str: def repl(m: re.Match) -> str: url = m.group(1) label = m.group(2) if label and label != url: return f"{label} ({url})" return url return SLACK_URL_PATTERN.sub(repl, text) def normalize_special_mentions(text: str) -> str: return SLACK_SPECIAL_MENTION_PATTERN.sub(r"@\1", text) def unescape_html_entities(text: str) -> str: def repl(m: re.Match) -> str: return _HTML_ENTITIES.get(m.group(1), m.group(0)) return SLACK_HTML_ENTITY_PATTERN.sub(repl, text) def normalize_slack_text(text: str) -> str: text = normalize_channel_refs(text) text = normalize_urls(text) text = normalize_special_mentions(text) text = unescape_html_entities(text) return text.strip()