From a74778e047a0b902e2d8653b9491e1dbb282c008 Mon Sep 17 00:00:00 2001 From: Corban-Lee Date: Thu, 4 Jul 2024 20:24:34 +0100 Subject: [PATCH] mutators as classes --- src/mutators.py | 519 ++++++++++++++++++++++++++---------------------- 1 file changed, 277 insertions(+), 242 deletions(-) diff --git a/src/mutators.py b/src/mutators.py index aed8056..616c7b5 100644 --- a/src/mutators.py +++ b/src/mutators.py @@ -1,160 +1,129 @@ +from abc import ABC, abstractmethod import random -import uwuify - -# For l33t sp34k translation -leet_map = {'a': '4', 'e': '3', 'i': '1', 'o': '0', 's': '5', 't': '7'} - -# For upside-down translation -upside_down_dict = str.maketrans( - "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890,.!?\"'", - "ɐqɔpǝɟƃɥᴉɾʞlɯuodbɹsʇnʌʍxʎz∀BↃᗡƎℲ⅁HIſ⋊⅃WNOԀΌᴚS⊥∩ΛMX⅄Z⇂2Ɛᔭ59Ɫ860˙‘¡¿,'" -) - -# For gothic script -gothic_dict = { - 'a': '𝔞', 'b': '𝔟', 'c': '𝔠', 'd': '𝔡', 'e': '𝔢', 'f': '𝔣', 'g': '𝔤', 'h': '𝔥', 'i': '𝔦', 'j': '𝔧', - 'k': '𝔨', 'l': '𝔩', 'm': '𝔪', 'n': '𝔫', 'o': '𝔬', 'p': '𝔭', 'q': '𝔮', 'r': '𝔯', 's': '𝔰', 't': '𝔱', - 'u': '𝔲', 'v': '𝔳', 'w': '𝔴', 'x': '𝔵', 'y': '𝔶', 'z': '𝔷', 'A': '𝔄', 'B': '𝔅', 'C': 'ℭ', 'D': '𝔇', - 'E': '𝔈', 'F': '𝔉', 'G': '𝔊', 'H': 'ℌ', 'I': 'ℑ', 'J': '𝔍', 'K': '𝔎', 'L': '𝔏', 'M': '𝔐', 'N': '𝔑', - 'O': '𝔒', 'P': '𝔓', 'Q': '𝔔', 'R': 'ℜ', 'S': '𝔖', 'T': '𝔗', 'U': '𝔘', 'V': '𝔙', 'W': '𝔚', 'X': '𝔛', - 'Y': '𝔜', 'Z': 'ℨ' -} - -# For emoji substitution -emoji_dict = { - 'a': '🇦', 'b': '🇧', 'c': '🇨', 'd': '🇩', 'e': '🇪', 'f': '🇫', 'g': '🇬', 'h': '🇭', 'i': '🇮', - 'j': '🇯', 'k': '🇰', 'l': '🇱', 'm': '🇲', 'n': '🇳', 'o': '🇴', 'p': '🇵', 'q': '🇶', 'r': '🇷', - 's': '🇸', 't': '🇹', 'u': '🇺', 'v': '🇻', 'w': '🇼', 'x': '🇽', 'y': '🇾', 'z': '🇿' -} - -# For Zalgo translation -zalgo_chars = [chr(random.randint(768, 879)) for _ in range(3)] - -# For morse code translation -morse_code_dict = { - 'A': '.-', 'B': '-...', 'C': '-.-.', 'D': '-..', 'E': '.', 'F': '..-.', 'G': '--.', 'H': '....', - 'I': '..', 'J': '.---', 'K': '-.-', 'L': '.-..', 'M': '--', 'N': '-.', 'O': '---', 'P': '.--.', - 'Q': '--.-', 'R': '.-.', 'S': '...', 'T': '-', 'U': '..-', 'V': '...-', 'W': '.--', 'X': '-..-', - 'Y': '-.--', 'Z': '--..', '1': '.----', '2': '..---', '3': '...--', '4': '....-', '5': '.....', - '6': '-....', '7': '--...', '8': '---..', '9': '----.', '0': '-----', ',': '--..--', '.': '.-.-.-', - '?': '..--..', '/': '-..-.', '-': '-....-', '(': '-.--.', ')': '-.--.-', ' ': '/' -} +from uwuipy import Uwuipy -class Mutator: - pass - - -class SubstututionCipher(Mutator): - def apply(text: str, cipher: dict[str, str]): - return "".join(cipher.get(c.lower(), c) for c in text) - - -def uwu(text: str) -> str: +class MutatorRegistry: """ - Returns an 'uwuified' version of the given string. + Registry for tracking and retrieving mutators. """ - return uwuify.uwu(text) + def __init__(self): + self._registry = {} -def gibberish(text: str) -> str: + def register(self, name: str, mutator_class): + self._registry[name] = mutator_class + + def get_mutator(self, name: str, *args, **kwargs): + mutator_class = self._registry.get(name) + if mutator_class is None: + raise ValueError(f"Mutator '{name}' not found in registry.") + return mutator_class(*args, **kwargs) + + +class TextMutator(ABC): """ - Returns a given string, but each character is randomy re-ordered. + Mutates given text. """ - return " ".join(["".join( - random.sample(word, len(word))) - for word in text.split() - ]) + @abstractmethod + def mutate(self, text: str) -> str: + pass -def leet(text: str) -> str: + +class Uwuify(TextMutator): """ - Translates a given string into 'l33t sp34k' and returns it. + Returns an 'uwuified' version of any given text. """ - return "".join([ - leet_map.get(char.lower(), char) - for char in text.upper() - ]) + def mutate(self, text: str, nsfw=False) -> str: + uwu = Uwuipy(None, 0.3, 0.3, 0.3, 1, False, 2) + return uwu.uwuify(text) -def reverse(text: str) -> str: - """ - Returns the passed string in reverse. - """ - return text[::-1] +class UwuifyNSFW(TextMutator): + """""" -def shuffle(text: str) -> str: - """ - Returns a given string, where each word is randomly shuffled. - """ + def mutate(self, text: str) -> str: + return Uwuify().mutate(text, nsfw=True) - words = text.split() - random.shuffle(words) - return " ".join(words) -def pig_latin(text: str) -> str: - """ - Takes a given string, translates it to 'pig latin' and returns it. - """ +class Gibberish(TextMutator): + def mutate(self, text: str) -> str: + return " ".join(["".join(random.sample(word, len(word))) for word in text.split()]) - def _pig_latin_word(word: str) -> str: - first_vowel = 0 - for char in word: - if char in "aeiou": - break - first_vowel += 1 +class LeetSpeak(TextMutator): + def mutate(self, text: str) -> str: + return "".join(self.leet_map.get(char.lower(), char) for char in text.upper()) - if first_vowel == 0: - return word + "way" - else: - return word[first_vowel:] + word[:first_vowel] + "ay" +class ReverseText(TextMutator): + def mutate(self, text: str) -> str: + return text[::-1] - return " ".join([_pig_latin_word(word) for word in text.split()]) -def random_case(text: str) -> str: - """ - Randomly converts each character of a given string to upper - or lower case, and returns the result. - """ +class ShuffleWords(TextMutator): + def mutate(self, text: str) -> str: + words = text.split() + random.shuffle(words) + return " ".join(words) - return "".join([ - char.upper() if random.random() > 0.5 else char.lower() - for char in text - ]) -def upside_down_text(text: str) -> str: - """ - Returns an upside-down translation of the given string. - """ +class PigLatin(TextMutator): + def mutate(self, text: str) -> str: + return " ".join([self._pig_latin_word(word) for word in text.split()]) - return text.translate(upside_down_dict)[::-1] + def _pig_latin_word(self, word: str) -> str: + for i, char in enumerate(word): + if char not in "aeiou": + continue -def gothic_script(text: str) -> str: - """ - Returns a 'gothic script' version of the given string. - """ + return word + "way" if i == 0 else word[i:] + word[:i] + "ay" - return ''.join(gothic_dict.get(c, c) for c in text) + return word + "way" -def emoji_substitution(text: str) -> str: - """ - Uses an emoji substitution sipher on the given string, - and returns the result. - """ - return ''.join(emoji_dict.get(c.lower(), c) for c in text) +class RandomiseCase(TextMutator): + def mutate(self, text: str) -> str: + return "".join(char.upper() if random.random() > .5 else char.lower() for char in text) -def small_caps(text: str) -> str: - """ - Translates a given string to it's small caps ascii counterpart, - and returns the result. - """ - def _to_small_caps(c: str) -> str: +class UpsideDown(TextMutator): + _upside_down_dict = str.maketrans( + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890,.!?\"'", + "ɐqɔpǝɟƃɥᴉɾʞlɯuodbɹsʇnʌʍxʎz∀BↃᗡƎℲ⅁HIſ⋊⅃WNOԀΌᴚS⊥∩ΛMX⅄Z⇂2Ɛᔭ59Ɫ860˙‘¡¿,'" + ) + + def mutate(self, text: str) -> str: + return text.translate(self._upside_down_dict)[::-1] + + +class GothicScript(TextMutator): + _gothic_dict = { + 'a': '𝔞', 'b': '𝔟', 'c': '𝔠', 'd': '𝔡', 'e': '𝔢', 'f': '𝔣', 'g': '𝔤', 'h': '𝔥', 'i': '𝔦', 'j': '𝔧', + 'k': '𝔨', 'l': '𝔩', 'm': '𝔪', 'n': '𝔫', 'o': '𝔬', 'p': '𝔭', 'q': '𝔮', 'r': '𝔯', 's': '𝔰', 't': '𝔱', + 'u': '𝔲', 'v': '𝔳', 'w': '𝔴', 'x': '𝔵', 'y': '𝔶', 'z': '𝔷', 'A': '𝔄', 'B': '𝔅', 'C': 'ℭ', 'D': '𝔇', + 'E': '𝔈', 'F': '𝔉', 'G': '𝔊', 'H': 'ℌ', 'I': 'ℑ', 'J': '𝔍', 'K': '𝔎', 'L': '𝔏', 'M': '𝔐', 'N': '𝔑', + 'O': '𝔒', 'P': '𝔓', 'Q': '𝔔', 'R': 'ℜ', 'S': '𝔖', 'T': '𝔗', 'U': '𝔘', 'V': '𝔙', 'W': '𝔚', 'X': '𝔛', + 'Y': '𝔜', 'Z': 'ℨ' + } + + def mutate(self, text: str) -> str: + return "".join(self._gothic_dict(char, char) for char in text) + + +class EmojiSubstitution(TextMutator): + def mutate(self, text: str) -> str: + return "".join(self._emoji_dict.get(char.lower(), char) for char in text) + + +class SmallCaps(TextMutator): + def mutate(self, text: str) -> str: + return "".join(self._small_cap(char) for char in text) + + def _small_cap(char: str) -> str: if "a" <= c <= "z": return chr(ord(c) + 0x1D00 - ord("a")) elif "A" <= c <= "Z": @@ -162,153 +131,219 @@ def small_caps(text: str) -> str: else: return c - return ''.join(_to_small_caps(c) for c in text) -def zalgo(text: str) -> str: - return "".join( - c + "".join(random.choices( - zalgo_chars, k=random.randint(1, 3) - )) for c in text - ) +class Zalgo(TextMutator): + _zalgo_chars = [chr(random.randint(768, 879)) for _ in range(3)] -def morse_code(text: str) -> str: - return " ".join(morse_code_dict.get(c.upper(), c) for c in text) + def mutate(self, text: str) -> str: + return "".join( + char + "".join(random.choices(self._zalgo_chars, k=random.randint(1, 3))) for char in text + ) -def to_binary(text: str) -> str: - return ' '.join(format(ord(c), '08b') for c in text) -def to_hexadecimal(text: str) -> str: - return ' '.join(format(ord(c), '02x') for c in text) +class MorseCode(TextMutator): + _morse_code_dict = { + 'A': '.-', 'B': '-...', 'C': '-.-.', 'D': '-..', 'E': '.', 'F': '..-.', 'G': '--.', 'H': '....', + 'I': '..', 'J': '.---', 'K': '-.-', 'L': '.-..', 'M': '--', 'N': '-.', 'O': '---', 'P': '.--.', + 'Q': '--.-', 'R': '.-.', 'S': '...', 'T': '-', 'U': '..-', 'V': '...-', 'W': '.--', 'X': '-..-', + 'Y': '-.--', 'Z': '--..', '1': '.----', '2': '..---', '3': '...--', '4': '....-', '5': '.....', + '6': '-....', '7': '--...', '8': '---..', '9': '----.', '0': '-----', ',': '--..--', '.': '.-.-.-', + '?': '..--..', '/': '-..-.', '-': '-....-', '(': '-.--.', ')': '-.--.-', ' ': '/' + } -def remove_vowels(text: str) -> str: - return ''.join(c for c in text if c.lower() not in 'aeiou') + def mutate(self, text: str) -> str: + return " ".join(self._morse_code_dict.get(char.upper(), char) for char in text) -def double_characters(text: str) -> str: - return ''.join(c*2 for c in text) -def randomly_inserted_emoji(text: str) -> str: - emojis = ['😀', '😂', '😍', '😎', '😊', '😜'] - return ' '.join(word + random.choice(emojis) for word in text.split()) +class ToBinary(TextMutator): + def mutate(self, text: str) -> str: + return " ".join(format(ord(c), '08b') for c in text) -def baby_talk(text: str) -> str: - replacements = {'r': 'w', 'l': 'w', 'th': 'd', 'u': 'oo'} - baby_text = [] - for word in text.split(): - for k, v in replacements.items(): - word = word.replace(k, v) - baby_text.append(word) - return " ".join(baby_text) -def pirate_speak(text: str) -> str: - replacements = {'hello': 'ahoy', 'my': 'me', 'friend': 'matey', 'is': 'be', 'am': 'be', 'are': 'be'} - pirate_text = [ - replacements.get(word.lower(), word) - for word in text.split() - ] - return " ".join(pirate_text) + ", arrr!" +class ToHexadecimal(TextMutator): + def mutate(self, text: str) -> str: + return " ".join(format(ord(c), '02x') for c in text) -def valley_girl(text: str) -> str: - valley_text = [] - for word in text.split(): - valley_text.append(word) - if random.random() < 0.3: - valley_text.append("like") - return ' '.join(valley_text) + ", you know?" +class RemoveVowels(TextMutator): + def mutate(self, text: str) -> str: + return "".join(char for char in text if char.lower() not in "aeiou") -def degeneracy(text: str) -> str: - cute_phrases = ['kawaii', 'nya~', 'uwu', '^_^', 'rawr'] - cute_text = [] - for word in text.split(): - cute_text.append(word) - if random.random() < 0.3: - cute_text.append(random.choice(cute_phrases)) - return " ".join(cute_text) -def cat_speak(text: str) -> str: - cat_text = [] - for word in text.split(): - cat_text.append(word) - if random.random() < 0.3: - cat_text.append('meow') +class DoubleCharacters(TextMutator): + def mutate(self, text: str) -> str: + return "".join(char*2 for char in text) - return " ".join(cat_text) -def nerdify(text: str) -> str: - text.replace(".", "☝️🤓.") - return text +class BabyTalk(TextMutator): + def mutate(self, text: str) -> str: + replacements = {"r": "w", "l": "w", "th": "d", "u": "oo"} + baby_text = [] -def backward_words(text: str) -> str: - return ' '.join(word[::-1] for word in text.split()) + for word in text.split(): + for k, v in replacements.items(): + word = word.replace(k, v) + baby_text.append(word) -def random_gibberish(text: str) -> str: - gibberish_words = ['blorpy', 'snorf', 'flibber', 'zoodle', 'womp', 'glarb'] - words = text.split() - return ' '.join(random.choice(gibberish_words) if random.random() < 0.3 else word for word in words) + return " ".join(baby_text) -def insert_random_animal_sounds(text: str) -> str: - animal_sounds = ['moo', 'oink', 'meow', 'woof', 'quack', 'neigh'] - result = [] - for word in text.split(): - result.append(word) - if random.random() < 0.3: - result.append(random.choice(animal_sounds)) - return ' '.join(result) -def shakespearean_speak(text: str) -> str: - shakespearean_dict = { +# def randomly_inserted_emoji(text: str) -> str: +# emojis = ['😀', '😂', '😍', '😎', '😊', '😜'] +# return ' '.join(word + random.choice(emojis) for word in text.split()) + +# def baby_talk(text: str) -> str: +# replacements = {'r': 'w', 'l': 'w', 'th': 'd', 'u': 'oo'} +# baby_text = [] +# for word in text.split(): +# for k, v in replacements.items(): +# word = word.replace(k, v) +# baby_text.append(word) +# return " ".join(baby_text) + +# def pirate_speak(text: str) -> str: +# replacements = {'hello': 'ahoy', 'my': 'me', 'friend': 'matey', 'is': 'be', 'am': 'be', 'are': 'be'} +# pirate_text = [ +# replacements.get(word.lower(), word) +# for word in text.split() +# ] +# return " ".join(pirate_text) + ", arrr!" + +# def valley_girl(text: str) -> str: +# valley_text = [] +# for word in text.split(): +# valley_text.append(word) +# if random.random() < 0.3: +# valley_text.append("like") + +# return ' '.join(valley_text) + ", you know?" + +# def degeneracy(text: str) -> str: +# cute_phrases = ['kawaii', 'nya~', 'uwu', '^_^', 'rawr'] +# cute_text = [] +# for word in text.split(): +# cute_text.append(word) +# if random.random() < 0.3: +# cute_text.append(random.choice(cute_phrases)) +# return " ".join(cute_text) + +# def cat_speak(text: str) -> str: +# cat_text = [] +# for word in text.split(): +# cat_text.append(word) +# if random.random() < 0.3: +# cat_text.append('meow') + +# return " ".join(cat_text) + +# def nerdify(text: str) -> str: +# text.replace(".", "☝️🤓.") +# return text + + +class BackwardsWords(TextMutator): + def mutate(self, text: str) -> str: + " ".join(word[::-1] for word in text.split()) + + +# def random_gibberish(text: str) -> str: +# gibberish_words = ['blorpy', 'snorf', 'flibber', 'zoodle', 'womp', 'glarb'] +# words = text.split() +# return ' '.join(random.choice(gibberish_words) if random.random() < 0.3 else word for word in words) + +# def insert_random_animal_sounds(text: str) -> str: +# animal_sounds = ['moo', 'oink', 'meow', 'woof', 'quack', 'neigh'] +# result = [] +# for word in text.split(): +# result.append(word) +# if random.random() < 0.3: +# result.append(random.choice(animal_sounds)) +# return ' '.join(result) + + +class ShakeSpearean(TextMutator): + _shakespearean_dict = { 'you': 'thou', 'your': 'thy', 'you\'re': 'thou art', 'are': 'art', 'am': 'am', 'is': 'is', 'have': 'hast', 'will': 'wilt', 'today': 'this day', 'hello': 'hail', 'goodbye': 'farewell' } - words = text.split() - return ' '.join(shakespearean_dict.get(word.lower(), word) for word in words) -def robot_speak(text: str) -> str: - robot_noises = ['beep', 'boop', 'whirr', 'click', 'buzz'] - words = text.split() - return ' '.join(random.choice(robot_noises) if word.isalpha() and random.random() < 0.2 else word for word in words) + def mutate(self, text: str) -> str: + return " ".join(self._shakespearean_dict.get(word.lower(), word) for word in text.split()) -def emojify(text: str) -> str: - emoji_dict = { - 'happy': '😄', 'sad': '😢', 'angry': '😡', 'love': '❤️', 'laugh': '😂', 'cry': '😭', 'sleepy': '😴', - 'surprise': '😮', 'cool': '😎', 'fire': '🔥', 'party': '🎉', 'star': '⭐' - } - words = text.split() - return ' '.join(emoji_dict.get(word.lower(), word) for word in words) + +# def robot_speak(text: str) -> str: +# robot_noises = ['beep', 'boop', 'whirr', 'click', 'buzz'] +# words = text.split() +# return ' '.join(random.choice(robot_noises) if word.isalpha() and random.random() < 0.2 else word for word in words) + +# def emojify(text: str) -> str: +# emoji_dict = { +# 'happy': '😄', 'sad': '😢', 'angry': '😡', 'love': '❤️', 'laugh': '😂', 'cry': '😭', 'sleepy': '😴', +# 'surprise': '😮', 'cool': '😎', 'fire': '🔥', 'party': '🎉', 'star': '⭐' +# } +# words = text.split() +# return ' '.join(emoji_dict.get(word.lower(), word) for word in words) # Maps instructions for an Article item to mutate attributes. -mutator_map = { - "UWU": uwu, - "GIB": gibberish, - "L3": leet, - "REV": reverse, - "RND": shuffle, - "PGL": pig_latin, - "RNC": random_case, - "UDT": upside_down_text, - "GS": gothic_script, - "EMJ": emoji_substitution, - "SML": small_caps, - "ZGO": zalgo, - "MC": morse_code, - "BIN": to_binary, - "HEX": to_hexadecimal, - "RMV": remove_vowels, - "DBL": double_characters, - "RNE": randomly_inserted_emoji, - "PIR": pirate_speak, - "VAL": valley_girl, - "DEG": degeneracy, - "CAT": cat_speak, - "NRD": nerdify, - "BKW": backward_words, - "RNG": lambda: None, - "RAS": lambda: None, - "SHK": lambda: None, - "RBT": lambda: None, - "EMI": lambda: None, -} \ No newline at end of file +# mutator_map = { +# "UWU": uwu, +# "GIB": gibberish, +# "L3": leet, +# "REV": reverse, +# "RND": shuffle, +# "PGL": pig_latin, +# "RNC": random_case, +# "UDT": upside_down_text, +# "GS": gothic_script, +# "EMJ": emoji_substitution, +# "SML": small_caps, +# "ZGO": zalgo, +# "MC": morse_code, +# "BIN": to_binary, +# "HEX": to_hexadecimal, +# "RMV": remove_vowels, +# "DBL": double_characters, +# "RNE": randomly_inserted_emoji, +# "PIR": pirate_speak, +# "VAL": valley_girl, +# "DEG": degeneracy, +# "CAT": cat_speak, +# "NRD": nerdify, +# "BKW": backward_words, +# "RNG": lambda: None, +# "RAS": lambda: None, +# "SHK": lambda: None, +# "RBT": lambda: None, +# "EMI": lambda: None, +# } + + +registry = MutatorRegistry() + +r = registry # shorthand, im not repeating this one hundred times +r.register("uwuify", Uwuify) +r.register("uwuify_nsfw", UwuifyNSFW) +r.register("gibberish", Gibberish) +r.register("leet_speak", LeetSpeak) +r.register("reverse_text", ReverseText) +r.register("shuffle_words", ShuffleWords) +r.register("pig_latin", PigLatin) +r.register("rnd_case", RandomiseCase) +r.register("flipped", UpsideDown) +r.register("gothic", GothicScript) +r.register("emj_substitute", EmojiSubstitution) +r.register("small_caps", SmallCaps) +r.register("zalgo", Zalgo) +r.register("morse_code", MorseCode) +r.register("to_bin", ToBinary) +r.register("to_hex", ToHexadecimal) +r.register("rm_vowels", RemoveVowels) +r.register("dbl_chars", DoubleCharacters) +r.register("backwards_words", BackwardsWords) +r.register("shakespear", ShakeSpearean) +# r.register("", ) +