2026-05-12 00:48:57 +08:00
|
|
|
from __future__ import annotations
|
|
|
|
|
|
|
|
|
|
import re
|
|
|
|
|
|
|
|
|
|
SLACK_MENTION_STRIP_PATTERN = re.compile(r"<@[^>\s]+>")
|
2026-05-12 14:51:53 +08:00
|
|
|
SLACK_CHANNEL_PATTERN = re.compile(r"<#([A-Z0-9]+)(?:\|([^>]+))?>")
|
|
|
|
|
SLACK_URL_PATTERN = re.compile(r"<(https?://[^|>]+)(?:\|([^>]+))?>")
|
|
|
|
|
SLACK_SUBTEAM_PATTERN = re.compile(r"<!subteam\^([A-Z0-9]+)(?:\|([^>]+))?>")
|
|
|
|
|
SLACK_SPECIAL_MENTION_PATTERN = re.compile(r"<!([^>]+)>")
|
|
|
|
|
SLACK_HTML_ENTITY_PATTERN = re.compile(r"&(amp|lt|gt|quot);")
|
|
|
|
|
|
|
|
|
|
_HTML_ENTITIES = {"amp": "&", "lt": "<", "gt": ">", "quot": '"'}
|
2026-05-12 00:48:57 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
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)
|
2026-05-12 14:51:53 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
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()
|