Files
namechecker-v2/name_checker_v2.py

189 lines
6.9 KiB
Python
Raw Permalink 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.
"""
Verbesserter Vorname-Checker für AntiSpamBot
Normailsiert dekorative Unicode-Schriftarten und entfernt Emojis
"""
import unicodedata
# Erweiterte Vokal-Liste (inkl. Umlaute und Y)
VOWELS = {
'a', 'e', 'i', 'o', 'u', 'ä', 'ö', 'ü', 'y',
'A', 'E', 'I', 'O', 'U', 'Ä', 'Ö', 'Ü', 'Y'
}
def is_emoji(char: str) -> bool:
"""Prüft ob ein Zeichen ein Emoji ist"""
if len(char) != 1:
return False
codepoint = ord(char)
# Emoji Unicode-Bereiche
return (
(0x1F600 <= codepoint <= 0x1F64F) or # Emoticons
(0x1F300 <= codepoint <= 0x1F5FF) or # Symbols & Pictographs
(0x1F680 <= codepoint <= 0x1F6FF) or # Transport & Map
(0x1F1E0 <= codepoint <= 0x1F1FF) or # Flags
(0x2600 <= codepoint <= 0x26FF) or # Misc Symbols
(0x2700 <= codepoint <= 0x27BF) or # Dingbats
(0xFE00 <= codepoint <= 0xFE0F) or # Variation Selectors
(0x1F900 <= codepoint <= 0x1F9FF) or # Supplemental Symbols
(0x1FA00 <= codepoint <= 0x1FA6F) or # Chess Symbols
(0x1FA70 <= codepoint <= 0x1FAFF) # Symbols and Pictographs Extended-A
)
def remove_emojis(text: str) -> str:
"""Entfernt alle Emojis aus dem Text"""
return ''.join(char for char in text if not is_emoji(char))
def normalize_decorative_fonts(text: str) -> str:
"""
Wandelt dekorative Unicode-Schriftarten in normale Buchstaben um.
Beispiele:
- 𝔐𝔞𝔵 → Max (Mathematical Bold)
- 𝒶𝒷𝒸 → abc (Mathematical Script)
- 𝓍𝓎𝓏 → xyz (Mathematical Bold Script)
- 𝖬𝖺𝗑 → Max (Sans-serif Bold)
- 𝙼𝚊𝚡 → Max (Monospace)
- ᴀʙᴄ → ABC (Small Caps)
"""
normalized = []
for char in text:
# Unicode-Kategorie prüfen
category = unicodedata.category(char)
# Wenn es ein Buchstabe ist, normalisieren wir
if char.isalpha():
# NFKD Decomposition: 𝔐 (U+1D510) → M + ◌̈ (wird zu M)
decomposed = unicodedata.normalize('NFKD', char)
# Nur den Basis-Buchstaben nehmen (erstes Zeichen nach Decomposition)
base_char = decomposed[0] if decomposed else char
# Zusätzliche manuelle Mappings für spezielle Mathematische Zeichen
# Die NFKD macht schon viel, aber wir sichern ab
if len(base_char) == 1 and base_char.isalpha():
normalized.append(base_char)
else:
# Fallback: Versuche den Codepoint zu mappen
normalized.append(char)
else:
# Nicht-Buchstaben (Zahlen, Symbole, etc.) behalten wir vorerst
normalized.append(char)
return ''.join(normalized)
def extract_first_real_chars(text: str, count: int = 5) -> str:
"""
Extrahiert die ersten 'count' Buchstaben aus dem Text,
ignoriert Emojis und Sonderzeichen.
"""
letters_only = []
for char in text:
if char.isalpha():
letters_only.append(char)
if len(letters_only) >= count:
break
return ''.join(letters_only)
def has_vowel_in_first_chars(name: str, max_position: int = 5) -> tuple[bool, str, str]:
"""
Prüft ob ein Vorname einen Vokal in den ersten max_position Buchstaben hat.
Args:
name: Der Vorname (kann mit Emojis/dekorativen Schriften sein)
max_position: Bis zu welchem Buchstaben geprüft wird (Standard: 5)
Returns:
(has_vowel: bool, cleaned_name: str, first_chars: str)
- has_vowel: True wenn Vokal gefunden, False wenn nicht
- cleaned_name: Der bereinigte Name (ohne Emojis, normalisiert)
- first_chars: Die ersten X Buchstaben die geprüft wurden
"""
# Schritt 1: Original für Logging
original = name
# Schritt 2: Emojis entfernen
name_no_emoji = remove_emojis(name)
# Schritt 3: Dekorative Schriften normalisieren
name_normalized = normalize_decorative_fonts(name_no_emoji)
# Schritt 4: Zu lowercase für Vergleich
name_lower = name_normalized.lower()
# Schritt 5: Erste X Buchstaben extrahieren
first_chars = extract_first_real_chars(name_lower, max_position)
# Schritt 6: Auf Vokale prüfen
found_vowels = [char for char in first_chars if char in VOWELS]
has_vowel = len(found_vowels) > 0
return has_vowel, name_normalized, first_chars, found_vowels
# Für Kompatibilität mit bestehendem Code
def check_name(name: str) -> bool:
"""
Einfache Wrapper-Funktion für den bestehenden Code.
Gibt True zurück wenn Vokal gefunden wurde (also KEIN Ban nötig).
Gibt False zurück wenn KEIN Vokal gefunden wurde (also potenzieller Spam).
"""
has_vowel, _, _, _ = has_vowel_in_first_chars(name, max_position=5)
return has_vowel
# Test-Beispiele
if __name__ == "__main__":
test_names = [
("Max", True, "Normaler Name"),
("🔥Max", True, "Emoji + Vorname"),
("🔥🔥Max", True, "Mehrere Emojis"),
("✨𝓜𝓪𝔁✨", True, "Dekorative Schriften mit Emojis"),
("𝔐𝔞𝔵𝔪𝔲𝔰𝕥𝔢𝔯", True, "Nur dekorative Schriften"),
("𝒶𝒷𝒸𝒹𝑒𝒻", False, "Nur Konsonanten in dekorativer Schrift"),
("Xyz", False, "Nur Konsonanten (kein Vorname)"),
("12345", False, "Nur Zahlen"),
("🔥Xyz123", False, "Emoji + Konsonanten + Zahlen"),
("Lynn", True, "Y als Vokal"),
("Fynn", True, "Y als Vokal"),
("Müller", True, "Deutscher Name mit Umlaut"),
("Jörg", True, "Deutscher Name mit Umlaut"),
("Ärger", True, "Deutscher Name mit Ä"),
("🔥Müller", True, "Emoji + Deutscher Name"),
("𝕄ü𝕝𝕝𝕖𝕣", True, "Dekorativ + Umlaut"),
("𝓜𝓪𝔁𝓶𝓾𝓼𝓽𝓮𝓻", True, "Langer Name mit Vokalen"),
("", False, "Leerer Name"),
("🔥✨💯", False, "Nur Emojis"),
]
print("=" * 60)
print("VORNAME-CHECKER v2.0 - Test Ergebnisse")
print("=" * 60)
passed = 0
failed = 0
for name, expected, description in test_names:
has_vowel, cleaned, first_chars, found_vowels = has_vowel_in_first_chars(name)
status = "" if has_vowel == expected else ""
if has_vowel == expected:
passed += 1
else:
failed += 1
status = "❌ FEHLER!"
print(f"\n{status} Test: {description}")
print(f" Original: '{name}'")
print(f" Bereinigt: '{cleaned}'")
print(f" Erste 5: '{first_chars}'")
print(f" Vokale: {found_vowels if found_vowels else 'KEINE'}")
print(f" Erwartet: {'Vokal' if expected else 'KEIN Vokal'}")
print(f" Ergebnis: {'Vokal' if has_vowel else 'KEIN Vokal'}")
print("\n" + "=" * 60)
print(f"Tests: {passed} bestanden, {failed} fehlgeschlagen")
print("=" * 60)