Files
PolyWeather/src/bot/command_parser.py
T

95 lines
2.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from __future__ import annotations
import re
import unicodedata
from typing import Any
from typing import Iterable
from typing import Tuple
_SLASH_CHARS = "//⁄∕╱⧸"
_COMMAND_RE = re.compile(
rf"^[\s\u00A0]*[{re.escape(_SLASH_CHARS)}]\s*([A-Za-z0-9_]+)(?:@([A-Za-z0-9_]+))?",
flags=re.ASCII,
)
def _clean_text(text: str | None) -> str:
raw = str(text or "")
if not raw:
return ""
cleaned: list[str] = []
for ch in raw:
code = ord(ch)
if 0xFE00 <= code <= 0xFE0F:
continue
if 0xE0100 <= code <= 0xE01EF:
continue
if unicodedata.category(ch) == "Cf":
continue
cleaned.append(ch)
normalized = "".join(cleaned).strip()
if not normalized:
return ""
for slash in ("", "", "", "", ""):
normalized = normalized.replace(slash, "/")
return normalized
def _parse_command_token(text: str | None) -> Tuple[str, str]:
normalized = _clean_text(text)
if not normalized:
return ("", "")
match = _COMMAND_RE.match(normalized)
if not match:
return ("", "")
command = str(match.group(1) or "").strip().lower()
username = str(match.group(2) or "").strip().lower()
return (command, username)
def extract_command_token(
text: str | None,
entities: Iterable[Any] | None = None,
) -> Tuple[str, str]:
raw = str(text or "")
if entities:
for entity in entities:
if str(getattr(entity, "type", "") or "").strip() != "bot_command":
continue
try:
offset = int(getattr(entity, "offset", 0) or 0)
length = int(getattr(entity, "length", 0) or 0)
except Exception:
continue
if length <= 0:
continue
fragment = raw[offset : offset + length]
command, username = _parse_command_token(fragment)
if command:
return (command, username)
return _parse_command_token(raw)
def extract_command_name(text: str | None, entities: Iterable[Any] | None = None) -> str:
return extract_command_token(text, entities)[0]
def looks_like_slash_command(text: str | None) -> bool:
normalized = _clean_text(text)
if not normalized:
return False
return normalized[:1] == "/"
def split_command_and_args(text: str | None) -> Tuple[str, str]:
normalized = _clean_text(text)
if not normalized:
return ("", "")
match = _COMMAND_RE.match(normalized)
if not match:
return ("", "")
command = str(match.group(1) or "").strip().lower()
rest = normalized[match.end() :].lstrip()
return (command, rest)