diff options
| author | 2019-09-03 09:05:12 -0700 | |
|---|---|---|
| committer | 2019-09-03 09:05:12 -0700 | |
| commit | 877d0886b1015e6c47d65bc2b5948de186951e4e (patch) | |
| tree | b1f30522c8dca6fdc3c7084772fa9fd3f458b94b /bot | |
| parent | Merge pull request #265 from vivax3794/losing_addintions (diff) | |
| parent | Improve wording of message conversion function (diff) | |
Merge pull request #260 from kosayoda/text-modify
Modify text :-)
Diffstat (limited to 'bot')
| -rw-r--r-- | bot/seasons/evergreen/fun.py | 57 | ||||
| -rw-r--r-- | bot/utils/__init__.py | 56 | 
2 files changed, 109 insertions, 4 deletions
| diff --git a/bot/seasons/evergreen/fun.py b/bot/seasons/evergreen/fun.py index ce3484f7..87077f36 100644 --- a/bot/seasons/evergreen/fun.py +++ b/bot/seasons/evergreen/fun.py @@ -2,20 +2,34 @@ import logging  import random  from discord.ext import commands +from discord.ext.commands import Bot, Cog, Context, MessageConverter +from bot import utils  from bot.constants import Emojis  log = logging.getLogger(__name__) +UWU_WORDS = { +    "fi": "fwi", +    "l": "w", +    "r": "w", +    "th": "d", +    "thing": "fing", +    "tho": "fo", +    "you're": "yuw'we", +    "your": "yur", +    "you": "yuw", +} -class Fun(commands.Cog): + +class Fun(Cog):      """A collection of general commands for fun.""" -    def __init__(self, bot): +    def __init__(self, bot: Bot) -> None:          self.bot = bot      @commands.command() -    async def roll(self, ctx, num_rolls: int = 1): +    async def roll(self, ctx: Context, num_rolls: int = 1) -> None:          """Outputs a number of random dice emotes (up to 6)."""          output = ""          if num_rolls > 6: @@ -27,8 +41,43 @@ class Fun(commands.Cog):              output += getattr(Emojis, terning, '')          await ctx.send(output) +    @commands.command(name="uwu", aliases=("uwuwize", "uwuify",)) +    async def uwu_command(self, ctx: Context, *, text: str) -> None: +        """Converts a given `text` into it's uwu equivalent.""" +        text = await Fun.get_discord_message(ctx, text) +        converted = utils.replace_many(text, UWU_WORDS, ignore_case=True, match_case=True) +        await ctx.send(f">>> {converted}") + +    @commands.command(name="randomcase", aliases=("rcase", "randomcaps", "rcaps",)) +    async def randomcase_command(self, ctx: Context, *, text: str) -> None: +        """Randomly converts the casing of a given `text`.""" +        text = await Fun.get_discord_message(ctx, text) +        converted = ( +            char.upper() if round(random.random()) else char.lower() for char in text +        ) +        await ctx.send(f">>> {''.join(converted)}") + +    @staticmethod +    async def get_discord_message(ctx: Context, text: str) -> str: +        """ +        Attempts to convert a given `text` to a discord Message object, then return the contents. + +        Useful if the user enters a link or an id to a valid Discord message, because the contents +        of the message get returned. + +        Returns `text` if the conversion fails. +        """ +        try: +            message = await MessageConverter().convert(ctx, text) +        except commands.BadArgument: +            log.debug(f"Input '{text:.20}...' is not a valid Discord Message") +        else: +            text = message.content +        finally: +            return text + -def setup(bot): +def setup(bot) -> None:      """Fun Cog load."""      bot.add_cog(Fun(bot))      log.info("Fun cog loaded") diff --git a/bot/utils/__init__.py b/bot/utils/__init__.py index 15c4b5db..3249a9cf 100644 --- a/bot/utils/__init__.py +++ b/bot/utils/__init__.py @@ -1,4 +1,6 @@  import asyncio +import re +import string  from typing import List  import discord @@ -71,3 +73,57 @@ async def disambiguate(          return entries[index - 1]      except IndexError:          raise BadArgument('Invalid choice.') + + +def replace_many( +        sentence: str, replacements: dict, *, ignore_case: bool = False, match_case: bool = False +) -> str: +    """ +    Replaces multiple substrings in a string given a mapping of strings. + +    By default replaces long strings before short strings, and lowercase before uppercase. +    Example: +        var = replace_many("This is a sentence", {"is": "was", "This": "That"}) +        assert var == "That was a sentence" + +    If `ignore_case` is given, does a case insensitive match. +    Example: +        var = replace_many("THIS is a sentence", {"IS": "was", "tHiS": "That"}, ignore_case=True) +        assert var == "That was a sentence" + +    If `match_case` is given, matches the case of the replacement with the replaced word. +    Example: +        var = replace_many( +            "This IS a sentence", {"is": "was", "this": "that"}, ignore_case=True, match_case=True +        ) +        assert var == "That WAS a sentence" +    """ +    if ignore_case: +        replacements = dict( +            (word.lower(), replacement) for word, replacement in replacements.items() +        ) + +    words_to_replace = sorted(replacements, key=lambda s: (-len(s), s)) + +    # Join and compile words to replace into a regex +    pattern = "|".join(re.escape(word) for word in words_to_replace) +    regex = re.compile(pattern, re.I if ignore_case else 0) + +    def _repl(match): +        """Returns replacement depending on `ignore_case` and `match_case`""" +        word = match.group(0) +        replacement = replacements[word.lower() if ignore_case else word] + +        if not match_case: +            return replacement + +        # Clean punctuation from word so string methods work +        cleaned_word = word.translate(str.maketrans('', '', string.punctuation)) +        if cleaned_word.isupper(): +            return replacement.upper() +        elif cleaned_word[0].isupper(): +            return replacement.capitalize() +        else: +            return replacement.lower() + +    return regex.sub(_repl, sentence) | 
