diff --git a/.config/systemd/user/banterbot.service b/.config/systemd/user/banterbot.service index 112e910..0b43f1a 100755 --- a/.config/systemd/user/banterbot.service +++ b/.config/systemd/user/banterbot.service @@ -4,7 +4,7 @@ After=banterbot.service [Service] Type=simple -ExecStart=/home/krowbar/Code/irc/banterbot.py -s 127.0.0.1 -p 6667 -n banterbot -c #tildetown #bots +ExecStart=/home/krowbar/Code/irc/bot_launcher.py -s 127.0.0.1 -p 6667 -n banterbot -c #tildetown #bots WorkingDirectory=/home/krowbar/Code/irc/ Restart=always RestartSec=5 diff --git a/.config/systemd/user/tildebot.service b/.config/systemd/user/tildebot.service index f16f0da..f537579 100755 --- a/.config/systemd/user/tildebot.service +++ b/.config/systemd/user/tildebot.service @@ -4,7 +4,7 @@ After=tildebot.service [Service] Type=simple -ExecStart=/home/krowbar/Code/irc/tildebot.py -s 127.0.0.1:6667 -n tildebot -c #bots +ExecStart=/home/krowbar/Code/irc/bot_launcher.py -n tildebot -s 127.0.0.1 -p 6667 -c #bots WorkingDirectory=/home/krowbar/Code/irc/ Restart=always RestartSec=5 diff --git a/.config/systemd/user/topicbot.service b/.config/systemd/user/topicbot.service index 99c5784..101cdc6 100755 --- a/.config/systemd/user/topicbot.service +++ b/.config/systemd/user/topicbot.service @@ -4,7 +4,7 @@ After=topicbot.service [Service] Type=simple -ExecStart=/home/krowbar/Code/irc/topicbot.py -s 127.0.0.1:6667 -n topicbot -c #tildetown #bots +ExecStart=/home/krowbar/Code/irc/banterbot.py -s 127.0.0.1 -p 6667 -n topicbot -c #bot_test WorkingDirectory=/home/krowbar/Code/irc/ Restart=always RestartSec=5 diff --git a/.tracery/aphorism b/.tracery/aphorism index 49c8046..9cfd111 100644 --- a/.tracery/aphorism +++ b/.tracery/aphorism @@ -7,8 +7,8 @@ "#animal.a# in the #bodypart# is #preposition# #number# in the #plant#", "#noun.a# is only as #adjective# as its #comparative# #noun#", "#animal.a# is #person.a#'s #comparative# #relation#", - "#person.ae# and #pronoun_possessive# #money# are #adverb# #verb#ed", - "#adjective.a# #noun#is the of #comparative# #noun.s#", + "#person.a# and #pronoun_possessive# #money# are #adverb# #verb#ed", + "#adjective.a# #noun# is the #noun# of #comparative# #noun.s#", "#person.a# in #verb# is #person.a# #adverb#", "#comparative.a# #noun# makes #comparative.a# #noun#", "#person.a# of #adjective# #noun.s# is #person# of #adjective#", diff --git a/Code/irc/acronymFinder.py b/Code/irc/acronymFinder.py deleted file mode 100644 index 1b83c92..0000000 --- a/Code/irc/acronymFinder.py +++ /dev/null @@ -1,99 +0,0 @@ -#!/usr/bin/python3 -import urllib -from bs4 import BeautifulSoup -import random -import string - -dict = "/usr/share/dict/american-english" -(userId, token) = open("/home/krowbar/.secret/s4token").readline().rstrip().split(",") - - -def get_acros(word, silly, short): - acros = [] - url = "http://www.stands4.com/services/v2/abbr.php?uid={}&tokenid={}&term={}".format( - userId, token, word - ) - soup = BeautifulSoup(urllib.request.urlopen(url).read(), "html5lib") - results = soup.find_all("result") - # there are lots of cases where the same definition is repeated multiple times under different categories. this is dumb so we should do a little more work - defs = [] - for r in results: - rdef = r.find("definition").text - match = next((x for x in defs if x["definition"].lower() == rdef.lower()), None) - if match is not None: - # if we find a match, add the category to the existing categories and increase the score - match["categories"].append( - ( - (r.find("parentcategoryname").text + "\\") - if r.find("parentcategoryname") - else "" - ) - + r.find("categoryname").text - ) - match["score"] = str(float(match["score"]) + float(r.find("score").text)) - else: # add a new item - defs.append( - { - "term": r.find("term").text, - "definition": r.find("definition").text, - "categories": [ - ( - (r.find("parentcategoryname").text + "\\") - if r.find("parentcategoryname") - else "" - ) - + r.find("categoryname").text - ], - "score": r.find("score").text, - } - ) - - for d in sorted(defs, key=lambda x: float(x["score"]), reverse=True): - # print d; - if short is True: - acros.append('"%s"' % d["definition"]) - else: - acros.append( - ( - '{}: "{}" ({}, score: {})'.format( - d["term"], - d["definition"], - ", ".join(d["categories"]), - d["score"], - ) - ) - ) - if silly is True: - newDef = [] - words = open(dict, "r").readlines() - try: - for idx, letter in enumerate(word): - newWord = random.choice( - list(filter( - lambda w: (idx is 0 or not w.strip().lower().endswith("'s")) - and w.lower().startswith(letter.lower()), - words, - )) - ).strip() - print(str(idx) + " -> " + newWord) - newDef.append(newWord) - newWord = string.capwords(" ".join(newDef)) - if short is True: - acros.append('"%s"' % newWord) - else: - acros.append( - ( - '{}: "{}" ({}, score: {})'.format( - word.upper(), newWord, "Tilde.town Original", "0" - ) - ) - ) - except IndexError: - acros.append("Future hazy, try again later: Tilde.town Error") - if short is True: - shortList = acros[0:5] - if len(acros) > 5: - shortList.append(acros[-1]) - return [word.upper() + ": " + ", ".join(shortList)] - else: - return acros diff --git a/Code/irc/banterbot.py b/Code/irc/banterbot.py deleted file mode 100755 index 380ccf0..0000000 --- a/Code/irc/banterbot.py +++ /dev/null @@ -1,64 +0,0 @@ -#!/usr/bin/python3 - -import argparse -from pinhook.bot import Bot - -parser = argparse.ArgumentParser() - -parser.add_argument( - "-s", - "--server", - dest="server", - default="127.0.0.1", - help="the server to connect to", - metavar="SERVER", -) -parser.add_argument( - "-p", - "--port", - dest="port", - type=int, - default=6667, - help="the port to connect to", - metavar="PORT", -) -parser.add_argument( - "-c", - "--channels", - dest="channels", - nargs="+", - default=["#bot_test"], - help="the channels to join", - metavar="CHANNELS", -) -parser.add_argument( - "-n", - "--nick", - dest="nick", - default="banterbot", - help="the nick to use", - metavar="NICK", -) -parser.add_argument( - "-o", - "--owner", - dest="owner", - default="krowbar", - help="the owner of this bot", - metavar="OWNER", -) - -args = parser.parse_args() -print(args) - -bot = Bot( - channels = args.channels, - nickname = args.nick, - ops = [ args.owner ], - plugin_dir = "{}_plugins".format(args.nick), - server = args.server, - port = args.port - ) - -if __name__ == "__main__": - bot.start() diff --git a/Code/irc/banterbot_legacy.py b/Code/irc/banterbot_legacy.py deleted file mode 100755 index 441bfd7..0000000 --- a/Code/irc/banterbot_legacy.py +++ /dev/null @@ -1,440 +0,0 @@ -#!/usr/bin/python3 -# using python3 because of unicode and crap -# http://wiki.shellium.org/w/Writing_an_IRC_bot_in_Python - -# Import some necessary libraries. -import argparse -import socket -import os -import sys -import fileinput -import random -import re -import subprocess -import textwrap -import time -import datetime - -import inflect -from rhymesWith import getRhymes -from rhymesWith import rhymeZone -from defineWord import defWord -import welch -import evil -import tumblr -import xkcdApropos -import wikiphilosophy -import acronymFinder -import util -from whosaid import whoSaid - -parser = argparse.ArgumentParser() - -parser.add_argument( - "-s", - "--server", - dest="server", - default="127.0.0.1:6667", - help="the server to connect to", - metavar="SERVER", -) -parser.add_argument( - "-c", - "--channels", - dest="channels", - nargs="+", - default=["#bot_test"], - help="the channels to join", - metavar="CHANNELS", -) -parser.add_argument( - "-n", - "--nick", - dest="nick", - default="banterbot_legacy", - help="the nick to use", - metavar="NICK", -) -parser.add_argument( - "-o", - "--owner", - dest="owner", - default="krowbar", - help="the owner of this bot", - metavar="OWNER", -) - -args = parser.parse_args() - -p = inflect.engine() - -def hello(): - util.sendmsg(ircsoc, channel, "Hello!") - - -def score_banter(channel, user, messageText): - score = 5 - with open("banterscores.txt", "r") as banterfile: - bantz = banterfile.readlines() - words = messageText.strip("\n").split(" ") - for word in words: - for bant in bantz: - bword = bant.strip("\n").split("|") - if re.sub("[^a-z0-9]+", "", word.lower()) == bword[0]: - score += int(bword[1]) - - score += messageText.count("!") * 2 # hype is banter - score -= messageText.count("!!!") * 6 # too much hype is not banter - score += messageText.count("#") * 3 # hashs are mad bantz - score -= messageText.count("##") * 6 # but too many is garbage - - names = ["mate", "lad", "my best boy"] - compliment = [ - "top-drawer", - "top-shelf", - "bangin'", - "legendary", - "smashing", - "incredible", - "impeccable", - "stunning", - ] - - msg = "" - if score > 100: - msg = "Truely {}, {}! That was some #banter! You earned a {} for that!".format( - random.choice(compliment).capitalize(), random.choice(names), score - ) - elif score > 50: - msg = "{} #banter! You get a {} from me!".format( - random.choice(compliment).capitalize(), score - ) - elif score > 10: - msg = "{} #banter. You get a {}".format( - random.choice(["acceptible", "reasonable", "passable"]).capitalize(), score - ) - else: - msg = "That {} #banter, {}. I'll give you a {}. Maybe try again?".format( - random.choice( - ["was hardly", "was barely", "wasn't", "won't pass for", "was awful"] - ), - random.choice(["lad", "lah", "boy", ""]), - score, - ) - - util.sendmsg(ircsock, channel, msg) - - -def get_new_banter(channel, user): - with open("/usr/share/dict/words", "r") as dict: - words = list(filter(lambda word: re.search(r"^[^']*$", word), dict.readlines())) - if random.randint(0, 1): # look for *ant words - words = list(filter(lambda word: re.search(r"ant", word), words)) - random.shuffle(words) - word = words[0].strip("\n") - start = word.find("ant") - if start == 0: - word = "b" + word - else: - if "aeiou".find(word[start]) > -1: # just append a 'b' - word = word[:start] + "b" + word[start:] - else: # replace the letter with 'b' - word = word[: start - 1] + "b" + word[start:] - else: # look for ban* words - words = list(filter(lambda word: re.search(r"ban", word), words)) - random.shuffle(words) - word = words[0].strip("\n") - end = word.find("ban") + 3 - if end == len(word): - word = word + "t" - else: - if "aeiou".find(word[end]) > -1: # just append 't' - word = word[:end] + "t" + word[end:] - else: # replace the letter with 'b' - word = word[:end] + "t" + word[end + 1 :] - util.sendmsg( - ircsock, channel, "{} : Here, why don't you try '{}'?".format(user, word) - ) - - -def get_rhymes(channel, user, text): - word = "" - if len(text.split(" ")) > 1: - word = text.split(" ")[1] - else: - with open("/home/nossidge/poems/words_poetic.txt", "r") as words: - word = random.choice(words.readlines()).strip("\n") - rhymes = rhymeZone(word) - if len(rhymes) == 0: - util.sendmsg( - ircsock, - channel, - "{}: Couldn't find anything that rhymes with '{}' :(".format(user, word), - ) - else: - util.sendmsg( - ircsock, - channel, - "{}: Here, these words rhyme with '{}': {}".format( - user, word, ", ".join(rhymes) - ), - ) - - -def define_word(channel, user, text): - word = "" - defs = [] - if len(text.split(" ")) > 1: - word = text.split(" ")[1] - defs = defWord(word) - if len(defs) == 0: - util.sendmsg( - ircsock, - channel, - "{}: Couldn't find the definition of '{}' :(".format(user, word), - ) - elif isinstance(defs, list): - for entry in defs: - util.sendmsg( - ircsock, channel, "{} : Define '{}' {}".format(user, word, entry[0:400]) - ) - else: - util.sendmsg( - ircsock, channel, "{} : Define '{}' {}".format(user, word, defs[0:400]) - ) - - -def make_rainbow(channel, user, text): - rbword = util.makeRainbow(text[9:]) - util.sendmsg(ircsock, channel, rbword) - - -def get_welch(channel): - util.sendmsg(ircsock, channel, welch.get_thing()[0:400]) - - -def get_evil(channel): - evilThing = evil.get_thing() - for line in [evilThing[i : i + 400] for i in range(0, len(evilThing), 400)]: - util.sendmsg(ircsock, channel, line) - - -def get_tumble(url, channel): - tumble = tumblr.tumble(url) - for line in [tumble[i : i + 400] for i in range(0, len(tumble), 400)]: - util.sendmsg(ircsock, channel, line) - - -def get_xkcd(channel, text): - links = xkcdApropos.xkcd(text[6:]) - joined_links = ", ".join(links) - for line in [joined_links[i : i + 400] for i in range(0, len(joined_links), 400)]: - util.sendmsg(ircsock, channel, line) - - -def get_wphilosophy(channel, text): - util.sendmsg(ircsock, channel, "Ok, give me a minute while I look up '{}'".format(text)) - steps = wikiphilosophy.get_philosophy_lower(text) - if not steps: - util.sendmsg( - ircsock, channel, "Couldn't find a wikipedia entry for {}".format(text) - ) - else: - joined_steps = " > ".join(steps) - if steps[-1] == "Philosophy": - joined_steps += "!!!" - for line in [ - joined_steps[i : i + 400] for i in range(0, len(joined_steps), 400) - ]: - util.sendmsg(ircsock, channel, line) - - -def figlet(channel, text): - if not text: - util.sendmsg(ircsock, channel, "No text given. :(") - else: - lines = subprocess.Popen( - ["figlet", "-w140"] + text.split(" "), shell=False, stdout=subprocess.PIPE - ).stdout.read().decode("utf-8") - for line in lines.split("\n"): - util.sendmsg(ircsock, channel, line) - time.sleep(0.4) # to avoid channel throttle due to spamming - - -def toilet(channel, text): - if not text: - util.sendmsg(ircsock, channel, "No text given. :(") - else: - lines = subprocess.Popen( - ["toilet", "-w140", "-F", "crop", "--irc"] + text.split(" "), - shell=False, - stdout=subprocess.PIPE, - ).stdout.read().decode("utf-8") - for line in lines.split("\n"): - util.sendmsg(ircsock, channel, line) - time.sleep(0.4) # to avoid channel throttle due to spamming - - -def get_acronym(channel, text): - if not text: - util.sendmsg(ircsock, channel, "No text given :(") - else: - defs = acronymFinder.get_acros(text, True, True) - for d in defs[0:5]: # only the first five. they are already sorted by 'score' - util.sendmsg(ircsock, channel, d) - if len(defs) > 5: - util.sendmsg(ircsock, channel, defs[-1]) - - -def get_whosaid(channel, text): - if not text: - util.sendmsg(ircsock, channel, " :No text given :(") - else: - result = whoSaid(text) - date = datetime.date.fromtimestamp(result["timecutoff"]) - dateStr = date.strftime("%B %d") - if not result["data"]: - msg = "Nobody said '%s' since %s" % (text, dateStr) - else: - msg = "Since %s, %s said '%s' %d times" % ( - dateStr, - result["data"][0][0], - text, - result["data"][0][1], - ) - if len(result["data"]) > 1: - msg += " and %s said it %d times" % ( - result["data"][1][0], - result["data"][1][1], - ) - util.sendmsg(ircsock, channel, msg) - - -def get_notice(user, channel): - util.notice(ircsock, user, channel, "Notice me senpai!") - - -def get_water(user, channel, msg, botnick): - if msg.find(botnick) == 0: - util.sendmsg(ircsock, channel, "Fight me, {}!".format(user)) - - -def mug_off(channel): - util.sendmsg(ircsock, channel, "u want some of this, m8?") - - -def rollcall(channel): - text = """ - U wot m8? I score all the top drawer #banter and #bantz on this channel! / Find new top-shelf banter with !newbanter [mungeWord [dictionary]], !rhymes, and !define. - Look up things with !acronym and !whosaid / Make your chatter #legend with !rainbow, !toilet, and !figlet. - Find interesting things with !xkcd and !wiki-philosophy / Get jokes with !welch !evil !kjp and !help - """ - for line in textwrap.dedent(text).split("\n"): - if line == "": - continue - util.sendmsg(ircsock, channel, line) - - -def listen(botnick): - while 1: # loop forever - - ircmsg = ircsock.recv(2048).decode('utf-8') - for msg in ircmsg.split("\n"): - msg = msg.strip("\n\r") - - if msg[:4] == "PING": - util.ping(ircsock, msg) - continue - - formatted = util.format_message(msg) - - if "" == formatted: - time.sleep(1) - continue - - # print(formatted) - - _time, user, _command, channel, messageText = formatted.split("\t") - - if messageText.find("#banter") != -1 or messageText.find("#bantz") != -1: - score_banter(channel, user, messageText) - - if messageText.startswith("!newbanter"): - get_new_banter(channel, user, messageText) - - if messageText.startswith("!rhymes"): - get_rhymes(channel, user, messageText) - - if messageText.startswith("!define"): - define_word(channel, user, messageText) - - if messageText.startswith("!rainbow"): - make_rainbow(channel, user, messageText) - - if messageText.startswith("!welch"): - get_welch(channel) - - if messageText.startswith("!evil"): - get_evil(channel) - - if messageText.startswith("!kjp"): - get_tumble("http://kingjamesprogramming.tumblr.com", channel) - - if messageText.startswith("!help"): - get_tumble("http://thedoomthatcametopuppet.tumblr.com", channel) - - if messageText.startswith("!xkcd"): - get_xkcd(channel, messageText) - - if messageText.startswith("!wiki-philosophy"): - get_wphilosophy(channel, messageText[17:]) - - if messageText.startswith("!figlet"): - figlet(channel, messageText[8:]) - - if messageText.startswith("!toilet"): - toilet(channel, messageText[8:]) - - if messageText.startswith("!acronym"): - get_acronym(channel, messageText[9:]) - - if messageText.startswith("!whosaid"): - get_whosaid(channel, messageText[9:]) - - if messageText.startswith("!notice"): - get_notice(user, channel) - - if messageText.startswith("!water"): - get_water(user, channel, messageText[7:], botnick) - - if messageText.startswith("!rollcall"): - rollcall(channel) - - if messageText.startswith(botnick + ":"): - mug_off(channel) - - if messageText.startswith("!join") and user == args.owner: - util.joinchan(ircsock, messageText[6:]) - - if messageText.startswith("!part") and user == args.owner: - util.part(ircsock, messageText[6:]) - - if messageText.startswith("!quit") and user == args.owner: - util.quit(ircsock, "Later chumps!") - return - - sys.stdout.flush() - time.sleep(1) - -if __name__ == "__main__": - # ROOT: i commented this out until it stops pegging the CPU. - # ~krowbar: this has the same logic loop as tildebot but for whatever reason - # it is banterbot that gets booted from IRC then rage-thrashes the machine - ircsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - util.connect(ircsock, args) - listen(args.nick) -else: - # create a fake socket that we'll use to just write to the screen - import mock - ircsock = mock.Mock() - # print("!! ircsock was not initialized! most methods will not work !!") diff --git a/Code/irc/banterbot_plugins/template.py b/Code/irc/banterbot_plugins/template.py deleted file mode 100644 index 8f79f8a..0000000 --- a/Code/irc/banterbot_plugins/template.py +++ /dev/null @@ -1,7 +0,0 @@ -#!/usr/bin/python3 - -import pinhook.plugin - -@pinhook.plugin.register('!') -def _plugin(msg): - return pinhook.plugin.message() diff --git a/Code/irc/banterbot_plugins/units.py b/Code/irc/banterbot_plugins/units.py new file mode 100644 index 0000000..af14fb3 --- /dev/null +++ b/Code/irc/banterbot_plugins/units.py @@ -0,0 +1,17 @@ +#!/usr/bin/python3 + +import pinhook.plugin +import subprocess + +UNITS_CMD = "/home/krowbar/Code/units/units-2.11/units" +UNITS_CFG = "/home/krowbar/Code/units/units-2.11/definitions.units" + +@pinhook.plugin.register('!units') +def units_plugin(msg): + if not msg.arg: + return pinhook.plugin.message("No text given. :(") + else: + result = subprocess.Popen( + [UNITS_CMD, "-v1f", UNITS_CFG] + msg.arg.split(" "), shell=False, stdout=subprocess.PIPE + ).stdout.read().decode("utf-8").strip() + return pinhook.plugin.message(result) diff --git a/Code/irc/banterbot_plugins/xkcd.py b/Code/irc/banterbot_plugins/xkcd.py index 3f358f9..f081cd7 100644 --- a/Code/irc/banterbot_plugins/xkcd.py +++ b/Code/irc/banterbot_plugins/xkcd.py @@ -1,8 +1,8 @@ #!/usr/bin/python3 import pinhook.plugin -from util import xkcdApropos +import util.xkcdApropos @pinhook.plugin.register('!xkcd') def xkcd_plugin(msg): - return pinhook.plugin.message(xkcdApropos.xkcd(msg.arg)) + return pinhook.plugin.message(util.xkcdApropos.xkcd(msg.arg)) diff --git a/Code/irc/badwords.txt b/Code/irc/data/badwords.txt similarity index 100% rename from Code/irc/badwords.txt rename to Code/irc/data/badwords.txt diff --git a/Code/irc/data/banter_corpus.txt b/Code/irc/data/banter_corpus.txt new file mode 100644 index 0000000..6b683b1 --- /dev/null +++ b/Code/irc/data/banter_corpus.txt @@ -0,0 +1,90 @@ +1418511761 karlen no more banter in the irc now +1421140177 jumblesale karlen yeah mate me too nice one banter +1421140187 karlen i bantered you right off there +1421140203 karlen Archbishop of Banterbury over here +1421140221 jumblesale "Archbishop of Banterbury" amazing +1421140286 karlen I can provide the Bantidote, I am a Bantersaurus Rex +1421140530 jumblesale 2nd wave banterism +1421239834 jumblesale I still can't get over the bishop of banterbury +1421239946 jumblesale all their faces covered by "archbishop of banterbury" in a monospaced font +1421240905 jumblesale archbishop of banterbury is too great for irc +1421244850 jumblesale fruminous bantersnatch +1421322755 karlen tbf I dont think he has as much banter as Rowan http://i.dailymail.co.uk/i/pix/2008/04_05/006Archbishop_228x388.jpg +1421322856 karlen they should just make the archbishop and this point: I am always bantering people off +1421322914 jumblesale banter +1421323249 jumblesale a tilde for top drawer banter? +1421323301 karlen ive spent the last 15mins looking for nowertb with banter but only one came up and its not bantz +1421323368 jumblesale banter +1421323895 karlen ok there will be a nowertb with banter in it at somepoint but its not bantz +1421323963 jumblesale how can you have banter and it not be legendary bantz? +1421324052 karlen It's comforting to realize that no one will ever read this.I am a quiet person for the most part. I mean, I talk, but most of the time it's preprogrammed banter just to pass time and please the people around me. +1421324515 karlen banter all over the world +1421325936 karlen haha there is a podcast they ahve called the Bantams banter I have heard mention of before +1421326023 karlen heard lots of Bantam banter when they beat Arsenal a season or two back +1421326312 karlen haha course, they bantered me off but such is life for a top drawer banter merchant such as myself +1421326892 karlen so that guy is called Carl Jenkison and he plays for Arsenal and hes a right top lad and every other word he says is literally banter +1421326918 karlen of banterbury +1421327028 karlen he's just a banter lad +1421327036 jumblesale karlen nobody's THAT banter +1421327168 karlen me too, will get something banter for lunch +1421328693 jumblesale how banter was your lunch? top drawer or legendary? +1421329045 jumblesale just putting together a little faw for banter +1421329247 karlen 1) What is banter 2) How to banter 3) How to banter someone off 4) Top bantz 5) Banter phrases +1421329333 karlen 6) Lad banter 7) Am I banter? 8) Banter resources 9) Examples of banter 10) When to banter +1421329371 karlen i'll put a banter file in my ~ and try to address some of these issues +1421330214 jumblesale karlen your banter contribution is legendary, I'll combine the two +1421330680 karlen ill try and think of some more once my banter juices have recharged +1421331867 jumblesale my dream is to travel anywhere in the world and immediately be able to banter off the first #lad I see +1421332132 karlen love your top banter phrases jumblesale +1421332270 jumblesale I love everything about your banter file karlen +1421332374 karlen feels wrong typing in less banter +1421332494 jumblesale banter +1421332676 jumblesale I go home. it's dark. I find a pen and hastily scrawl a note. "~wife. sorry. I can't be with you any more. I need banter. #legend". charles barks. he does not recognise me. I am a different man to the one who left this morning. I put the note on the table, collect my passport and step out into the night. somewhere out there a lad needs to be bantered off. and I am the only one who can do it. +1421332760 jumblesale we were just enjoying some banter. +1421337186 jumblesale nah mate just kidding it was shit #banter +1421337361 karlen i got bantered right off there +1421345107 jumblesale now we can finally get some top drawer banter going on +1421346140 krowbar jumblesale: u wot m80? i swear on me mum that's the worst idea i ever dun hear and you should be banned from new ideas. banter! +1421351218 karlen saw the bantz, not sure I deserve to be a notable banterer though compared to those ledge's +1421353890 jumblesale haha harmless banter :) +1421402562 karlen the banter zone +1421402670 karlen im sure dan has banter, its probably a commonwealth export +1421402740 karlen banter has probably spread there like the cane toad +1421402762 karlen they are a banterous people by nature if Foster's adverts are to be believed +1421402804 jumblesale banter = comedy +1421402887 karlen you removed my top banter pun, it was the one bit of bantz in that file worth while +1421402953 karlen from "turn your banter from piss poor to top drawer" +1421402982 karlen or something like that, I had to delete the file from my ~. I had exceeded my banter allowance according the du -BANTS +1421403014 karlen or quota -u -BANTER rather +1421403230 jumblesale http://tilde.town/~banter/ +1421403809 karlen wow, maybe they are the banter messiah?! +1421403998 jumblesale I saved your stuff to ~jumblesale/banter +1421404449 karlen just banter mate come on, didn't expect you to look. You've been bantered right off for caring +1421404474 jumblesale well I am going to add it back in put that in your banter pipe and bant it +1421404569 karlen ill be in banter space +1421404903 jumblesale I'm sorry karlen, the banter is fatal. It's spread to your brain. +1421424059 jumblesale karlen that's why they call you banter the magnificent +1421661838 karlen hey its jumblebanter! +1421661982 jumblesale spent all weekend getting bantered right off +1421661993 jumblesale now I'm seeing banter everywhere +1421662006 karlen mate you have taken the red banter pill +1421664295 jumblesale also where are you hanging around in the uk that has swastikas everywhere? are you that desparate for banter? +1421665117 karlen the dan and um zone is probably so banter +1421667558 karlen RogueLad: The banter chronicles +1421667703 jumblesale maybe when I quit here I'll have some time to put into RogueLad: The #banter Chronicles +1421667994 jumblesale Kragoth banters the kobold right off for 6 damage +1421668027 karlen KO: you have been bantered right off there. #DeadLad +1421678445 karlen haha we have to tone down the banter when we have company +1421678572 um You two can banter away as far as I'm concerned. +1421678645 jumblesale haha um you won't find it soothing when karlen banters you right off +1421678654 jumblesale just with his banter +1421678807 jumblesale mate I've been mugging off crustaceans since before you were born. think you can banter off a crab? fack off mate +1421678914 karlen Mate Crustaceans ain't shit. Wait till you banter off a Banatee +1421679040 jumblesale banatee might be a new low in banter punning +1421771342 karlen you are ascending the banter charts that is for sure +1421771528 karlen Mate, only in Ireland is that Banter +1421771917 karlen look what we did to this other guy! he didn't even get exposed! LabMateBanter http://cdn6.bigcommerce.com/s-vhn7zwb/products/452/images/411/eos_safe_showers_freeze__77418__05399.1405105554.1280.1280.jpg?c=2 +1421773775 krowbar i'm thinking of writing a banterbot for scoring #banter +1421773807 krowbar but i'll first need a corpus of #banter +1421773838 karlen mensch -q banter +1421773857 karlen or mensch -q "#banter" diff --git a/Code/irc/banterscores.txt b/Code/irc/data/banterscores.txt similarity index 100% rename from Code/irc/banterscores.txt rename to Code/irc/data/banterscores.txt diff --git a/Code/irc/numberwangscores.txt b/Code/irc/data/numberwangscores.txt similarity index 100% rename from Code/irc/numberwangscores.txt rename to Code/irc/data/numberwangscores.txt diff --git a/Code/irc/data/quotes.txt b/Code/irc/data/quotes.txt new file mode 100644 index 0000000..f0c07c2 --- /dev/null +++ b/Code/irc/data/quotes.txt @@ -0,0 +1,3 @@ +Bang a gong. Get it on. Bang a gong. +/T.Rex/ +--- diff --git a/Code/irc/randomtopics.txt b/Code/irc/data/randomtopics.txt similarity index 100% rename from Code/irc/randomtopics.txt rename to Code/irc/data/randomtopics.txt diff --git a/Code/irc/data/tildejackpot.txt b/Code/irc/data/tildejackpot.txt new file mode 100644 index 0000000..597975b --- /dev/null +++ b/Code/irc/data/tildejackpot.txt @@ -0,0 +1 @@ +35 \ No newline at end of file diff --git a/Code/irc/tildescores.txt b/Code/irc/data/tildescores.txt similarity index 89% rename from Code/irc/tildescores.txt rename to Code/irc/data/tildescores.txt index ca9792f..41cc9a0 100644 --- a/Code/irc/tildescores.txt +++ b/Code/irc/data/tildescores.txt @@ -1,4 +1,4 @@ -krowbar&^%2740&^%1548423098 +krowbar&^%2745&^%1548770703.413761 karlen&^%498&^%1527613440 endorphant&^%809&^%1444775660 jumblesale&^%25&^%1426171214 @@ -48,13 +48,13 @@ cinch&^%2&^%1480454755 caffbot&^%969&^%1532662872 evilbot&^%4&^%1480693919 tybaltcat&^%7&^%1481076625 -Minerbot&^%316&^%1548341661 +Minerbot&^%328&^%1548433782 mio&^%347&^%1529720473 tehfraga&^%673&^%1547260565 sushi&^%10&^%1493253212 troido&^%303&^%1548409580 gamebot&^%336&^%1548409599 -nilaky&^%1757&^%1548386011 +nilaky&^%1759&^%1548459568 bucket&^%103&^%1507931139 lolbot&^%1&^%1502568407 m455&^%12&^%1512076715 @@ -67,7 +67,7 @@ pinhook&^%8&^%1509744722 emfor&^%3&^%1509671353 k2l8m11n2&^%11&^%1510932395 sacredpixel&^%3&^%1522082931 -login&^%3249&^%1548423081 +login&^%3276&^%1548698114 kelpiebot&^%3&^%1513101957 unreal&^%2&^%1534387108 kinsey&^%26&^%1520446672 @@ -80,11 +80,11 @@ silver&^%9&^%1519333029 equa&^%53&^%1534373756 audiodude&^%2&^%1519453927 whimsy&^%47&^%1529678733 -wangofett&^%285&^%1547499873 +wangofett&^%286&^%1548446486 saturn&^%3&^%1521429369 lucidiot&^%28&^%1526201925 tracer&^%1&^%1521744878 -jan6&^%1346&^%1548353997 +jan6&^%1359&^%1548771222.440076 eeeeeta&^%55&^%1540361066 cmccabe&^%81&^%1529698164 carbon&^%9&^%1524135505 @@ -96,7 +96,7 @@ ralph&^%4&^%1526980620 von&^%490&^%1548233084 ensis&^%1750&^%1546853217 simon&^%26&^%1527937489 -benharri&^%3241&^%1548427827 +benharri&^%3276&^%1548695613 cpb&^%3&^%1528930564 calmbit&^%160&^%1541625694 wisebot&^%5652&^%1539612163 @@ -106,10 +106,10 @@ x4464&^%1&^%1532028546 pounce&^%19&^%1532133325 livix&^%7&^%1533603142 ben&^%3&^%1533767627 -npa&^%319&^%1548385964 +npa&^%326&^%1548659103 ezo&^%6&^%1533883842 aliasless&^%36&^%1541001821 -kirch&^%487&^%1548427938 +kirch&^%492&^%1548773313.169501 root&^%2&^%1535558514 byte&^%5&^%1536416308 qbe&^%7&^%1537850181 @@ -118,16 +118,16 @@ h00fi&^%1&^%1537050053 fantoro&^%57&^%1542125611 tildethief&^%7421&^%1542132794 benjaminwil&^%581&^%1548377274 -deltawitch&^%3451&^%1548192292 +deltawitch&^%3453&^%1548462217 archangelic&^%484&^%1541101297 diodelass&^%3&^%1539382302 -minerobber&^%420&^%1548341654 +minerobber&^%420&^%1548433750 brendantcc&^%3&^%1539908223 dozens&^%21&^%1541090333 bowlercaptain&^%6&^%1540926135 nicole&^%6&^%1541276844 littlebigly&^%49&^%1541283119 -ahriman&^%624&^%1548397580 +ahriman&^%636&^%1548663037 tunas&^%114&^%1545848648 netscape_navigator&^%5&^%1545846867 roan&^%5&^%1545846612 @@ -136,6 +136,6 @@ ben&^%3&^%1545800958 l0010o0001l&^%3&^%154529473 rgdrake&^%1&^%1546086404 handyc&^%5&^%1546456002 -fosslinux&^%8&^%1548296029 +fosslinux&^%10&^%1548661962 banterbot&^%3&^%1547588758 testgamebot&^%4&^%1547722176 diff --git a/Code/irc/topics_#bot_test.txt b/Code/irc/data/topics_#bot_test.txt similarity index 100% rename from Code/irc/topics_#bot_test.txt rename to Code/irc/data/topics_#bot_test.txt diff --git a/Code/irc/topics_#bots.txt b/Code/irc/data/topics_#bots.txt similarity index 100% rename from Code/irc/topics_#bots.txt rename to Code/irc/data/topics_#bots.txt diff --git a/Code/irc/topics_#tildetown.txt b/Code/irc/data/topics_#tildetown.txt similarity index 100% rename from Code/irc/topics_#tildetown.txt rename to Code/irc/data/topics_#tildetown.txt diff --git a/Code/irc/data/topics_now.txt b/Code/irc/data/topics_now.txt new file mode 100644 index 0000000..6128d08 --- /dev/null +++ b/Code/irc/data/topics_now.txt @@ -0,0 +1,2 @@ +1516797459&^%login&^% +1516797472&^%login&^% diff --git a/Code/irc/topicscores.txt b/Code/irc/data/topicscores.txt similarity index 100% rename from Code/irc/topicscores.txt rename to Code/irc/data/topicscores.txt diff --git a/Code/irc/defineWord.py b/Code/irc/defineWord.py deleted file mode 100644 index e7d977f..0000000 --- a/Code/irc/defineWord.py +++ /dev/null @@ -1,34 +0,0 @@ -#!/usr/bin/python3 -import urllib -from bs4 import BeautifulSoup -import random - - -def define(word): - defs = [] - url = "http://www.merriam-webster.com/dictionary/{}".format(word) - soup = BeautifulSoup(urllib.request.urlopen(url).read(), "html.parser") - head = soup.find("div", id="headword") - if head: - for p in head.find_all("p"): - defs.append(p.text) - return defs - - -key = open("/home/krowbar/.secret/key").readline().rstrip() - - -def defWord(word, short=True): - defs = [] - url = "http://www.dictionaryapi.com/api/v1/references/collegiate/xml/{}?key={}".format( - word, key - ) - soup = BeautifulSoup(urllib.request.urlopen(url).read(), "html5lib") - entry = soup.find("entry") - if entry: - for d in entry.find_all("dt"): - defs.append(d.text) - if short: - return " ".join(defs) - else: - return defs diff --git a/Code/irc/dict_puzzle.py b/Code/irc/dict_puzzle.py deleted file mode 100644 index 1bef24d..0000000 --- a/Code/irc/dict_puzzle.py +++ /dev/null @@ -1,53 +0,0 @@ -#!/usr/bin/python -import random -import inflect - -p = inflect.engine() -dictionary = "/usr/share/dict/american-english-small" -BAD_WORDS_FILE = "badwords.txt" - - -def gen_wordlist(): - # I feel weird calling this "get_wordlist" when it's a generator without calling out that I do in fact realise it's weird - ~deltawitch - # how about gen_wordlist - with open(BAD_WORDS_FILE, "r") as fp: - bad_words = set(fp) - - for word in open(dictionary).readlines(): - if "'" not in word and word not in bad_words: - yield word.rstrip() - - -def get_puzzle(): - dict_words = list(gen_wordlist()) - words = random.sample(dict_words, 3) - key = random.randrange(0, 3) # get values 1-3 - puzzle = "When alphebetized, what is the {} in {}?".format( - p.ordinal(p.number_to_words(key + 1)), ", ".join(words) - ) - words.sort() - answer = words[key] - return [answer, puzzle] - - -def get_anagram(maxlen=6): - dict_words = [ - word for word in gen_wordlist() if len(word) > 2 and len(word) < maxlen + 1 - ] - word = random.choice(dict_words) - anagram = list(word) - random.shuffle(anagram) - anagram = "".join(anagram) - - # Anagrams can have multiple answers, so we provide a check function that accepts all possibilities - def answer_checker(guess): - # Check for exact match - if guess == word: - return True - # Bail out early if they didn't even use all the same letters - if sorted(guess) != sorted(word): - return False - # Ok, gotta actually check if it's a word now - return any(guess == item for item in gen_wordlist()) - - return [answer_checker, "Unscramble the following word: '{}'".format(anagram)] diff --git a/Code/irc/duckduckgo.py b/Code/irc/duckduckgo.py deleted file mode 100755 index 767254e..0000000 --- a/Code/irc/duckduckgo.py +++ /dev/null @@ -1,198 +0,0 @@ -import requests -import urllib -import json as j -import sys - -__version__ = 0.242 - - -def query( - query, - useragent="python-duckduckgo " + str(__version__), - safesearch=True, - html=False, - meanings=True, - **kwargs -): - """ - Query DuckDuckGo, returning a Results object. - - Here's a query that's unlikely to change: - - >>> result = query('1 + 1') - >>> result.type - 'nothing' - >>> result.answer.text - '1 + 1 = 2' - >>> result.answer.type - 'calc' - - Keword arguments: - useragent: UserAgent to use while querying. Default: "python-duckduckgo %d" (str) - safesearch: True for on, False for off. Default: True (bool) - html: True to allow HTML in output. Default: False (bool) - meanings: True to include disambiguations in results (bool) - Any other keyword arguments are passed directly to DuckDuckGo as URL params. - """ % __version__ - - safesearch = "1" if safesearch else "-1" - html = "0" if html else "1" - meanings = "0" if meanings else "1" - params = { - "q": query, - "o": "json", - "kp": safesearch, - "no_redirect": "1", - "no_html": html, - "d": meanings, - } - params.update(kwargs) - encparams = urllib.parse.urlencode(params) - url = "http://api.duckduckgo.com/?" + encparams - - request = requests.get(url, headers={"User-Agent": useragent}) - - return Results(request.json()) - - -class Results(object): - def __init__(self, json): - self.type = { - "A": "answer", - "D": "disambiguation", - "C": "category", - "N": "name", - "E": "exclusive", - "": "nothing", - }.get(json.get("Type", ""), "") - - self.json = json - self.api_version = None # compat - - self.heading = json.get("Heading", "") - - self.results = [Result(elem) for elem in json.get("Results", [])] - self.related = [Result(elem) for elem in json.get("RelatedTopics", [])] - - self.abstract = Abstract(json) - self.redirect = Redirect(json) - self.definition = Definition(json) - self.answer = Answer(json) - - self.image = Image({"Result": json.get("Image", "")}) - - -class Abstract(object): - def __init__(self, json): - self.html = json.get("Abstract", "") - self.text = json.get("AbstractText", "") - self.url = json.get("AbstractURL", "") - self.source = json.get("AbstractSource") - - -class Redirect(object): - def __init__(self, json): - self.url = json.get("Redirect", "") - - -class Result(object): - def __init__(self, json): - self.topics = json.get("Topics", []) - if self.topics: - self.topics = [Result(t) for t in self.topics] - return - self.html = json.get("Result") - self.text = json.get("Text") - self.url = json.get("FirstURL") - - icon_json = json.get("Icon") - if icon_json is not None: - self.icon = Image(icon_json) - else: - self.icon = None - - -class Image(object): - def __init__(self, json): - self.url = json.get("Result") - self.height = json.get("Height", None) - self.width = json.get("Width", None) - - -class Answer(object): - def __init__(self, json): - self.text = json.get("Answer") - self.type = json.get("AnswerType", "") - - -class Definition(object): - def __init__(self, json): - self.text = json.get("Definition", "") - self.url = json.get("DefinitionURL") - self.source = json.get("DefinitionSource") - - -def get_zci( - q, - web_fallback=True, - priority=["answer", "abstract", "related.0", "definition"], - urls=True, - **kwargs -): - """A helper method to get a single (and hopefully the best) ZCI result. - priority=list can be used to set the order in which fields will be checked for answers. - Use web_fallback=True to fall back to grabbing the first web result. - passed to query. This method will fall back to 'Sorry, no results.' - if it cannot find anything.""" - - ddg = query("\\" + q, **kwargs) - response = "" - - for p in priority: - ps = p.split(".") - type = ps[0] - index = int(ps[1]) if len(ps) > 1 else None - - result = getattr(ddg, type) - if index is not None: - if not hasattr(result, "__getitem__"): - raise TypeError("%s field is not indexable" % type) - result = result[index] if len(result) > index else None - if not result: - continue - - if result.text: - response = result.text - if result.text and hasattr(result, "url") and urls: - if result.url: - response += " (%s)" % result.url - if response: - break - - # if there still isn't anything, try to get the first web result - if not response and web_fallback: - if ddg.redirect.url: - response = ddg.redirect.url - - # final fallback - if not response: - response = "Sorry, no results." - - return response - - -def main(): - if len(sys.argv) > 1: - q = query(" ".join(sys.argv[1:])) - keys = q.json.keys() - keys.sort() - for key in keys: - sys.stdout.write(key) - if type(q.json[key]) in [str, unicode]: - print(":", q.json[key]) - else: - sys.stdout.write("\n") - for i in q.json[key]: - print("\t", i) - else: - print("Usage: %s [query]" % sys.argv[0]) diff --git a/Code/irc/evil.py b/Code/irc/evil.py deleted file mode 100644 index eecb7f6..0000000 --- a/Code/irc/evil.py +++ /dev/null @@ -1,9 +0,0 @@ -import random - - -def get_thing(): - file = "/home/krowbar/logs/evildata.txt" - thing = "" - return ( - "If I Ever Become an Evil Overlord: " + random.choice(list(open(file))).rstrip() - ) diff --git a/Code/irc/formatter.pyc b/Code/irc/formatter.pyc deleted file mode 100644 index 48a929c..0000000 Binary files a/Code/irc/formatter.pyc and /dev/null differ diff --git a/Code/irc/get_users.pyc b/Code/irc/get_users.pyc deleted file mode 100644 index a422c78..0000000 Binary files a/Code/irc/get_users.pyc and /dev/null differ diff --git a/Code/irc/inflect.py b/Code/irc/inflect.py deleted file mode 100644 index f2db66b..0000000 --- a/Code/irc/inflect.py +++ /dev/null @@ -1,3981 +0,0 @@ -""" - inflect.py: correctly generate plurals, ordinals, indefinite articles; - convert numbers to words - Copyright (C) 2010 Paul Dyson - - Based upon the Perl module Lingua::EN::Inflect by Damian Conway. - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - - The original Perl module Lingua::EN::Inflect by Damian Conway is - available from http://search.cpan.org/~dconway/ - - This module can be downloaded at http://pypi.python.org/pypi/inflect - -methods: - classical inflect - plural plural_noun plural_verb plural_adj singular_noun no num a an - compare compare_nouns compare_verbs compare_adjs - present_participle - ordinal - number_to_words - join - defnoun defverb defadj defa defan - - INFLECTIONS: classical inflect - plural plural_noun plural_verb plural_adj singular_noun compare - no num a an present_participle - - PLURALS: classical inflect - plural plural_noun plural_verb plural_adj singular_noun no num - compare compare_nouns compare_verbs compare_adjs - - COMPARISONS: classical - compare compare_nouns compare_verbs compare_adjs - - ARTICLES: classical inflect num a an - - NUMERICAL: ordinal number_to_words - - USER_DEFINED: defnoun defverb defadj defa defan - -Exceptions: - UnknownClassicalModeError - BadNumValueError - BadChunkingOptionError - NumOutOfRangeError - BadUserDefinedPatternError - BadRcFileError - BadGenderError - -""" - -from re import match, search, subn, IGNORECASE, VERBOSE -from re import split as splitre -from re import error as reerror -from re import sub as resub - - -class UnknownClassicalModeError(Exception): - pass - - -class BadNumValueError(Exception): - pass - - -class BadChunkingOptionError(Exception): - pass - - -class NumOutOfRangeError(Exception): - pass - - -class BadUserDefinedPatternError(Exception): - pass - - -class BadRcFileError(Exception): - pass - - -class BadGenderError(Exception): - pass - - -__ver_major__ = 0 -__ver_minor__ = 2 -__ver_patch__ = 4 -__ver_sub__ = "" -__version__ = "%d.%d.%d%s" % (__ver_major__, __ver_minor__, __ver_patch__, __ver_sub__) - - -STDOUT_ON = False - - -def print3(txt): - if STDOUT_ON: - print(txt) - - -def enclose(s): - return "(?:%s)" % s - - -def joinstem(cutpoint=0, words=""): - """ - join stem of each word in words into a string for regex - each word is truncated at cutpoint - cutpoint is usually negative indicating the number of letters to remove - from the end of each word - - e.g. - joinstem(-2, ["ephemeris", "iris", ".*itis"]) returns - (?:ephemer|ir|.*it) - - """ - return enclose("|".join(w[:cutpoint] for w in words)) - - -def bysize(words): - """ - take a list of words and return a dict of sets sorted by word length - e.g. - ret[3]=set(['ant', 'cat', 'dog', 'pig']) - ret[4]=set(['frog', 'goat']) - ret[5]=set(['horse']) - ret[8]=set(['elephant']) - """ - ret = {} - for w in words: - if len(w) not in ret: - ret[len(w)] = set() - ret[len(w)].add(w) - return ret - - -def make_pl_si_lists(lst, plending, siendingsize, dojoinstem=True): - """ - given a list of singular words: lst - an ending to append to make the plural: plending - the number of characters to remove from the singular before appending plending: siendingsize - a flag whether to create a joinstem: dojoinstem - - return: - a list of pluralised words: si_list (called si because this is what you need to - look for to make the singular) - the pluralised words as a dict of sets sorted by word length: si_bysize - the singular words as a dict of sets sorted by word length: pl_bysize - if dojoinstem is True: a regular expression that matches any of the stems: stem - """ - if siendingsize is not None: - siendingsize = -siendingsize - si_list = [w[:siendingsize] + plending for w in lst] - pl_bysize = bysize(lst) - si_bysize = bysize(si_list) - if dojoinstem: - stem = joinstem(siendingsize, lst) - return si_list, si_bysize, pl_bysize, stem - else: - return si_list, si_bysize, pl_bysize - - -# 1. PLURALS - -pl_sb_irregular_s = { - "corpus": "corpuses|corpora", - "opus": "opuses|opera", - "genus": "genera", - "mythos": "mythoi", - "penis": "penises|penes", - "testis": "testes", - "atlas": "atlases|atlantes", - "yes": "yeses", -} - -pl_sb_irregular = { - "child": "children", - "brother": "brothers|brethren", - "loaf": "loaves", - "hoof": "hoofs|hooves", - "beef": "beefs|beeves", - "thief": "thiefs|thieves", - "money": "monies", - "mongoose": "mongooses", - "ox": "oxen", - "cow": "cows|kine", - "graffito": "graffiti", - "octopus": "octopuses|octopodes", - "genie": "genies|genii", - "ganglion": "ganglions|ganglia", - "trilby": "trilbys", - "turf": "turfs|turves", - "numen": "numina", - "atman": "atmas", - "occiput": "occiputs|occipita", - "sabretooth": "sabretooths", - "sabertooth": "sabertooths", - "lowlife": "lowlifes", - "flatfoot": "flatfoots", - "tenderfoot": "tenderfoots", - "romany": "romanies", - "jerry": "jerries", - "mary": "maries", - "talouse": "talouses", - "blouse": "blouses", - "rom": "roma", - "carmen": "carmina", -} - -pl_sb_irregular.update(pl_sb_irregular_s) -# pl_sb_irregular_keys = enclose('|'.join(pl_sb_irregular.keys())) - -pl_sb_irregular_caps = { - "Romany": "Romanies", - "Jerry": "Jerrys", - "Mary": "Marys", - "Rom": "Roma", -} - -pl_sb_irregular_compound = {"prima donna": "prima donnas|prime donne"} - -si_sb_irregular = dict([(v, k) for (k, v) in pl_sb_irregular.items()]) -keys = list(si_sb_irregular.keys()) -for k in keys: - if "|" in k: - k1, k2 = k.split("|") - si_sb_irregular[k1] = si_sb_irregular[k2] = si_sb_irregular[k] - del si_sb_irregular[k] -si_sb_irregular_caps = dict([(v, k) for (k, v) in pl_sb_irregular_caps.items()]) -si_sb_irregular_compound = dict([(v, k) for (k, v) in pl_sb_irregular_compound.items()]) -keys = list(si_sb_irregular_compound.keys()) -for k in keys: - if "|" in k: - k1, k2 = k.split("|") - si_sb_irregular_compound[k1] = si_sb_irregular_compound[ - k2 - ] = si_sb_irregular_compound[k] - del si_sb_irregular_compound[k] - -# si_sb_irregular_keys = enclose('|'.join(si_sb_irregular.keys())) - -# Z's that don't double - -pl_sb_z_zes_list = ("quartz", "topaz") -pl_sb_z_zes_bysize = bysize(pl_sb_z_zes_list) - -pl_sb_ze_zes_list = ("snooze",) -pl_sb_ze_zes_bysize = bysize(pl_sb_ze_zes_list) - - -# CLASSICAL "..is" -> "..ides" - -pl_sb_C_is_ides_complete = [ - # GENERAL WORDS... - "ephemeris", - "iris", - "clitoris", - "chrysalis", - "epididymis", -] - -pl_sb_C_is_ides_endings = [ - # INFLAMATIONS... - "itis" -] - -pl_sb_C_is_ides = joinstem( - -2, pl_sb_C_is_ides_complete + [".*%s" % w for w in pl_sb_C_is_ides_endings] -) - -pl_sb_C_is_ides_list = pl_sb_C_is_ides_complete + pl_sb_C_is_ides_endings - -( - si_sb_C_is_ides_list, - si_sb_C_is_ides_bysize, - pl_sb_C_is_ides_bysize, -) = make_pl_si_lists(pl_sb_C_is_ides_list, "ides", 2, dojoinstem=False) - - -# CLASSICAL "..a" -> "..ata" - -pl_sb_C_a_ata_list = ( - "anathema", - "bema", - "carcinoma", - "charisma", - "diploma", - "dogma", - "drama", - "edema", - "enema", - "enigma", - "lemma", - "lymphoma", - "magma", - "melisma", - "miasma", - "oedema", - "sarcoma", - "schema", - "soma", - "stigma", - "stoma", - "trauma", - "gumma", - "pragma", -) - -( - si_sb_C_a_ata_list, - si_sb_C_a_ata_bysize, - pl_sb_C_a_ata_bysize, - pl_sb_C_a_ata, -) = make_pl_si_lists(pl_sb_C_a_ata_list, "ata", 1) - -# UNCONDITIONAL "..a" -> "..ae" - -pl_sb_U_a_ae_list = ("alumna", "alga", "vertebra", "persona") -( - si_sb_U_a_ae_list, - si_sb_U_a_ae_bysize, - pl_sb_U_a_ae_bysize, - pl_sb_U_a_ae, -) = make_pl_si_lists(pl_sb_U_a_ae_list, "e", None) - -# CLASSICAL "..a" -> "..ae" - -pl_sb_C_a_ae_list = ( - "amoeba", - "antenna", - "formula", - "hyperbola", - "medusa", - "nebula", - "parabola", - "abscissa", - "hydra", - "nova", - "lacuna", - "aurora", - "umbra", - "flora", - "fauna", -) -( - si_sb_C_a_ae_list, - si_sb_C_a_ae_bysize, - pl_sb_C_a_ae_bysize, - pl_sb_C_a_ae, -) = make_pl_si_lists(pl_sb_C_a_ae_list, "e", None) - - -# CLASSICAL "..en" -> "..ina" - -pl_sb_C_en_ina_list = ("stamen", "foramen", "lumen") - -( - si_sb_C_en_ina_list, - si_sb_C_en_ina_bysize, - pl_sb_C_en_ina_bysize, - pl_sb_C_en_ina, -) = make_pl_si_lists(pl_sb_C_en_ina_list, "ina", 2) - - -# UNCONDITIONAL "..um" -> "..a" - -pl_sb_U_um_a_list = ( - "bacterium", - "agendum", - "desideratum", - "erratum", - "stratum", - "datum", - "ovum", - "extremum", - "candelabrum", -) -( - si_sb_U_um_a_list, - si_sb_U_um_a_bysize, - pl_sb_U_um_a_bysize, - pl_sb_U_um_a, -) = make_pl_si_lists(pl_sb_U_um_a_list, "a", 2) - -# CLASSICAL "..um" -> "..a" - -pl_sb_C_um_a_list = ( - "maximum", - "minimum", - "momentum", - "optimum", - "quantum", - "cranium", - "curriculum", - "dictum", - "phylum", - "aquarium", - "compendium", - "emporium", - "enconium", - "gymnasium", - "honorarium", - "interregnum", - "lustrum", - "memorandum", - "millennium", - "rostrum", - "spectrum", - "speculum", - "stadium", - "trapezium", - "ultimatum", - "medium", - "vacuum", - "velum", - "consortium", - "arboretum", -) - -( - si_sb_C_um_a_list, - si_sb_C_um_a_bysize, - pl_sb_C_um_a_bysize, - pl_sb_C_um_a, -) = make_pl_si_lists(pl_sb_C_um_a_list, "a", 2) - - -# UNCONDITIONAL "..us" -> "i" - -pl_sb_U_us_i_list = ( - "alumnus", - "alveolus", - "bacillus", - "bronchus", - "locus", - "nucleus", - "stimulus", - "meniscus", - "sarcophagus", -) -( - si_sb_U_us_i_list, - si_sb_U_us_i_bysize, - pl_sb_U_us_i_bysize, - pl_sb_U_us_i, -) = make_pl_si_lists(pl_sb_U_us_i_list, "i", 2) - -# CLASSICAL "..us" -> "..i" - -pl_sb_C_us_i_list = ( - "focus", - "radius", - "genius", - "incubus", - "succubus", - "nimbus", - "fungus", - "nucleolus", - "stylus", - "torus", - "umbilicus", - "uterus", - "hippopotamus", - "cactus", -) - -( - si_sb_C_us_i_list, - si_sb_C_us_i_bysize, - pl_sb_C_us_i_bysize, - pl_sb_C_us_i, -) = make_pl_si_lists(pl_sb_C_us_i_list, "i", 2) - - -# CLASSICAL "..us" -> "..us" (ASSIMILATED 4TH DECLENSION LATIN NOUNS) - -pl_sb_C_us_us = ( - "status", - "apparatus", - "prospectus", - "sinus", - "hiatus", - "impetus", - "plexus", -) -pl_sb_C_us_us_bysize = bysize(pl_sb_C_us_us) - -# UNCONDITIONAL "..on" -> "a" - -pl_sb_U_on_a_list = ( - "criterion", - "perihelion", - "aphelion", - "phenomenon", - "prolegomenon", - "noumenon", - "organon", - "asyndeton", - "hyperbaton", -) -( - si_sb_U_on_a_list, - si_sb_U_on_a_bysize, - pl_sb_U_on_a_bysize, - pl_sb_U_on_a, -) = make_pl_si_lists(pl_sb_U_on_a_list, "a", 2) - -# CLASSICAL "..on" -> "..a" - -pl_sb_C_on_a_list = ("oxymoron",) - -( - si_sb_C_on_a_list, - si_sb_C_on_a_bysize, - pl_sb_C_on_a_bysize, - pl_sb_C_on_a, -) = make_pl_si_lists(pl_sb_C_on_a_list, "a", 2) - - -# CLASSICAL "..o" -> "..i" (BUT NORMALLY -> "..os") - -pl_sb_C_o_i = [ - "solo", - "soprano", - "basso", - "alto", - "contralto", - "tempo", - "piano", - "virtuoso", -] # list not tuple so can concat for pl_sb_U_o_os - -pl_sb_C_o_i_bysize = bysize(pl_sb_C_o_i) -si_sb_C_o_i_bysize = bysize(["%si" % w[:-1] for w in pl_sb_C_o_i]) - -pl_sb_C_o_i_stems = joinstem(-1, pl_sb_C_o_i) - -# ALWAYS "..o" -> "..os" - -pl_sb_U_o_os_complete = set(("ado", "ISO", "NATO", "NCO", "NGO", "oto")) -si_sb_U_o_os_complete = set("%ss" % w for w in pl_sb_U_o_os_complete) - - -pl_sb_U_o_os_endings = [ - "aficionado", - "aggro", - "albino", - "allegro", - "ammo", - "Antananarivo", - "archipelago", - "armadillo", - "auto", - "avocado", - "Bamako", - "Barquisimeto", - "bimbo", - "bingo", - "Biro", - "bolero", - "Bolzano", - "bongo", - "Boto", - "burro", - "Cairo", - "canto", - "cappuccino", - "casino", - "cello", - "Chicago", - "Chimango", - "cilantro", - "cochito", - "coco", - "Colombo", - "Colorado", - "commando", - "concertino", - "contango", - "credo", - "crescendo", - "cyano", - "demo", - "ditto", - "Draco", - "dynamo", - "embryo", - "Esperanto", - "espresso", - "euro", - "falsetto", - "Faro", - "fiasco", - "Filipino", - "flamenco", - "furioso", - "generalissimo", - "Gestapo", - "ghetto", - "gigolo", - "gizmo", - "Greensboro", - "gringo", - "Guaiabero", - "guano", - "gumbo", - "gyro", - "hairdo", - "hippo", - "Idaho", - "impetigo", - "inferno", - "info", - "intermezzo", - "intertrigo", - "Iquico", - "jumbo", - "junto", - "Kakapo", - "kilo", - "Kinkimavo", - "Kokako", - "Kosovo", - "Lesotho", - "libero", - "libido", - "libretto", - "lido", - "Lilo", - "limbo", - "limo", - "lineno", - "lingo", - "lino", - "livedo", - "loco", - "logo", - "lumbago", - "macho", - "macro", - "mafioso", - "magneto", - "magnifico", - "Majuro", - "Malabo", - "manifesto", - "Maputo", - "Maracaibo", - "medico", - "memo", - "metro", - "Mexico", - "micro", - "Milano", - "Monaco", - "mono", - "Montenegro", - "Morocco", - "Muqdisho", - "myo", - "neutrino", - "Ningbo", - "octavo", - "oregano", - "Orinoco", - "Orlando", - "Oslo", - "panto", - "Paramaribo", - "Pardusco", - "pedalo", - "photo", - "pimento", - "pinto", - "pleco", - "Pluto", - "pogo", - "polo", - "poncho", - "Porto-Novo", - "Porto", - "pro", - "psycho", - "pueblo", - "quarto", - "Quito", - "rhino", - "risotto", - "rococo", - "rondo", - "Sacramento", - "saddo", - "sago", - "salvo", - "Santiago", - "Sapporo", - "Sarajevo", - "scherzando", - "scherzo", - "silo", - "sirocco", - "sombrero", - "staccato", - "sterno", - "stucco", - "stylo", - "sumo", - "Taiko", - "techno", - "terrazzo", - "testudo", - "timpano", - "tiro", - "tobacco", - "Togo", - "Tokyo", - "torero", - "Torino", - "Toronto", - "torso", - "tremolo", - "typo", - "tyro", - "ufo", - "UNESCO", - "vaquero", - "vermicello", - "verso", - "vibrato", - "violoncello", - "Virgo", - "weirdo", - "WHO", - "WTO", - "Yamoussoukro", - "yo-yo", - "zero", - "Zibo", -] + pl_sb_C_o_i - -pl_sb_U_o_os_bysize = bysize(pl_sb_U_o_os_endings) -si_sb_U_o_os_bysize = bysize(["%ss" % w for w in pl_sb_U_o_os_endings]) - - -# UNCONDITIONAL "..ch" -> "..chs" - -pl_sb_U_ch_chs_list = ("czech", "eunuch", "stomach") - -( - si_sb_U_ch_chs_list, - si_sb_U_ch_chs_bysize, - pl_sb_U_ch_chs_bysize, - pl_sb_U_ch_chs, -) = make_pl_si_lists(pl_sb_U_ch_chs_list, "s", None) - - -# UNCONDITIONAL "..[ei]x" -> "..ices" - -pl_sb_U_ex_ices_list = ("codex", "murex", "silex") -( - si_sb_U_ex_ices_list, - si_sb_U_ex_ices_bysize, - pl_sb_U_ex_ices_bysize, - pl_sb_U_ex_ices, -) = make_pl_si_lists(pl_sb_U_ex_ices_list, "ices", 2) - -pl_sb_U_ix_ices_list = ("radix", "helix") -( - si_sb_U_ix_ices_list, - si_sb_U_ix_ices_bysize, - pl_sb_U_ix_ices_bysize, - pl_sb_U_ix_ices, -) = make_pl_si_lists(pl_sb_U_ix_ices_list, "ices", 2) - -# CLASSICAL "..[ei]x" -> "..ices" - -pl_sb_C_ex_ices_list = ( - "vortex", - "vertex", - "cortex", - "latex", - "pontifex", - "apex", - "index", - "simplex", -) - -( - si_sb_C_ex_ices_list, - si_sb_C_ex_ices_bysize, - pl_sb_C_ex_ices_bysize, - pl_sb_C_ex_ices, -) = make_pl_si_lists(pl_sb_C_ex_ices_list, "ices", 2) - - -pl_sb_C_ix_ices_list = ("appendix",) - -( - si_sb_C_ix_ices_list, - si_sb_C_ix_ices_bysize, - pl_sb_C_ix_ices_bysize, - pl_sb_C_ix_ices, -) = make_pl_si_lists(pl_sb_C_ix_ices_list, "ices", 2) - - -# ARABIC: ".." -> "..i" - -pl_sb_C_i_list = ("afrit", "afreet", "efreet") - -(si_sb_C_i_list, si_sb_C_i_bysize, pl_sb_C_i_bysize, pl_sb_C_i) = make_pl_si_lists( - pl_sb_C_i_list, "i", None -) - - -# HEBREW: ".." -> "..im" - -pl_sb_C_im_list = ("goy", "seraph", "cherub") - -(si_sb_C_im_list, si_sb_C_im_bysize, pl_sb_C_im_bysize, pl_sb_C_im) = make_pl_si_lists( - pl_sb_C_im_list, "im", None -) - - -# UNCONDITIONAL "..man" -> "..mans" - -pl_sb_U_man_mans_list = """ - ataman caiman cayman ceriman - desman dolman farman harman hetman - human leman ottoman shaman talisman -""".split() -pl_sb_U_man_mans_caps_list = """ - Alabaman Bahaman Burman German - Hiroshiman Liman Nakayaman Norman Oklahoman - Panaman Roman Selman Sonaman Tacoman Yakiman - Yokohaman Yuman -""".split() - -( - si_sb_U_man_mans_list, - si_sb_U_man_mans_bysize, - pl_sb_U_man_mans_bysize, -) = make_pl_si_lists(pl_sb_U_man_mans_list, "s", None, dojoinstem=False) -( - si_sb_U_man_mans_caps_list, - si_sb_U_man_mans_caps_bysize, - pl_sb_U_man_mans_caps_bysize, -) = make_pl_si_lists(pl_sb_U_man_mans_caps_list, "s", None, dojoinstem=False) - - -pl_sb_uninflected_s_complete = [ - # PAIRS OR GROUPS SUBSUMED TO A SINGULAR... - "breeches", - "britches", - "pajamas", - "pyjamas", - "clippers", - "gallows", - "hijinks", - "headquarters", - "pliers", - "scissors", - "testes", - "herpes", - "pincers", - "shears", - "proceedings", - "trousers", - # UNASSIMILATED LATIN 4th DECLENSION - "cantus", - "coitus", - "nexus", - # RECENT IMPORTS... - "contretemps", - "corps", - "debris", - "siemens", - # DISEASES - "mumps", - # MISCELLANEOUS OTHERS... - "diabetes", - "jackanapes", - "series", - "species", - "subspecies", - "rabies", - "chassis", - "innings", - "news", - "mews", - "haggis", -] - -pl_sb_uninflected_s_endings = [ - # RECENT IMPORTS... - "ois", - # DISEASES - "measles", -] - -pl_sb_uninflected_s = pl_sb_uninflected_s_complete + [ - ".*%s" % w for w in pl_sb_uninflected_s_endings -] - -pl_sb_uninflected_herd = ( - # DON'T INFLECT IN CLASSICAL MODE, OTHERWISE NORMAL INFLECTION - "wildebeest", - "swine", - "eland", - "bison", - "buffalo", - "elk", - "rhinoceros", - "zucchini", - "caribou", - "dace", - "grouse", - "guinea fowl", - "guinea-fowl", - "haddock", - "hake", - "halibut", - "herring", - "mackerel", - "pickerel", - "pike", - "roe", - "seed", - "shad", - "snipe", - "teal", - "turbot", - "water fowl", - "water-fowl", -) - -pl_sb_uninflected_complete = [ - # SOME FISH AND HERD ANIMALS - "tuna", - "salmon", - "mackerel", - "trout", - "bream", - "sea-bass", - "sea bass", - "carp", - "cod", - "flounder", - "whiting", - "moose", - # OTHER ODDITIES - "graffiti", - "djinn", - "samuri", - "offspring", - "pence", - "quid", - "hertz", -] + pl_sb_uninflected_s_complete -# SOME WORDS ENDING IN ...s (OFTEN PAIRS TAKEN AS A WHOLE) - -pl_sb_uninflected_caps = [ - # ALL NATIONALS ENDING IN -ese - "Portuguese", - "Amoyese", - "Borghese", - "Congoese", - "Faroese", - "Foochowese", - "Genevese", - "Genoese", - "Gilbertese", - "Hottentotese", - "Kiplingese", - "Kongoese", - "Lucchese", - "Maltese", - "Nankingese", - "Niasese", - "Pekingese", - "Piedmontese", - "Pistoiese", - "Sarawakese", - "Shavese", - "Vermontese", - "Wenchowese", - "Yengeese", -] - - -pl_sb_uninflected_endings = [ - # SOME FISH AND HERD ANIMALS - "fish", - "deer", - "sheep", - # ALL NATIONALS ENDING IN -ese - "nese", - "rese", - "lese", - "mese", - # DISEASES - "pox", - # OTHER ODDITIES - "craft", -] + pl_sb_uninflected_s_endings -# SOME WORDS ENDING IN ...s (OFTEN PAIRS TAKEN AS A WHOLE) - - -pl_sb_uninflected_bysize = bysize(pl_sb_uninflected_endings) - - -# SINGULAR WORDS ENDING IN ...s (ALL INFLECT WITH ...es) - -pl_sb_singular_s_complete = [ - "acropolis", - "aegis", - "alias", - "asbestos", - "bathos", - "bias", - "bronchitis", - "bursitis", - "caddis", - "cannabis", - "canvas", - "chaos", - "cosmos", - "dais", - "digitalis", - "epidermis", - "ethos", - "eyas", - "gas", - "glottis", - "hubris", - "ibis", - "lens", - "mantis", - "marquis", - "metropolis", - "pathos", - "pelvis", - "polis", - "rhinoceros", - "sassafras", - "trellis", -] + pl_sb_C_is_ides_complete - - -pl_sb_singular_s_endings = ["ss", "us"] + pl_sb_C_is_ides_endings - -pl_sb_singular_s_bysize = bysize(pl_sb_singular_s_endings) - -si_sb_singular_s_complete = ["%ses" % w for w in pl_sb_singular_s_complete] -si_sb_singular_s_endings = ["%ses" % w for w in pl_sb_singular_s_endings] -si_sb_singular_s_bysize = bysize(si_sb_singular_s_endings) - -pl_sb_singular_s_es = ["[A-Z].*es"] - -pl_sb_singular_s = enclose( - "|".join( - pl_sb_singular_s_complete - + [".*%s" % w for w in pl_sb_singular_s_endings] - + pl_sb_singular_s_es - ) -) - - -# PLURALS ENDING IN uses -> use - - -si_sb_ois_oi_case = ("Bolshois", "Hanois") - -si_sb_uses_use_case = ("Betelgeuses", "Duses", "Meuses", "Syracuses", "Toulouses") - -si_sb_uses_use = ( - "abuses", - "applauses", - "blouses", - "carouses", - "causes", - "chartreuses", - "clauses", - "contuses", - "douses", - "excuses", - "fuses", - "grouses", - "hypotenuses", - "masseuses", - "menopauses", - "misuses", - "muses", - "overuses", - "pauses", - "peruses", - "profuses", - "recluses", - "reuses", - "ruses", - "souses", - "spouses", - "suffuses", - "transfuses", - "uses", -) - -si_sb_ies_ie_case = ( - "Addies", - "Aggies", - "Allies", - "Amies", - "Angies", - "Annies", - "Annmaries", - "Archies", - "Arties", - "Aussies", - "Barbies", - "Barries", - "Basies", - "Bennies", - "Bernies", - "Berties", - "Bessies", - "Betties", - "Billies", - "Blondies", - "Bobbies", - "Bonnies", - "Bowies", - "Brandies", - "Bries", - "Brownies", - "Callies", - "Carnegies", - "Carries", - "Cassies", - "Charlies", - "Cheries", - "Christies", - "Connies", - "Curies", - "Dannies", - "Debbies", - "Dixies", - "Dollies", - "Donnies", - "Drambuies", - "Eddies", - "Effies", - "Ellies", - "Elsies", - "Eries", - "Ernies", - "Essies", - "Eugenies", - "Fannies", - "Flossies", - "Frankies", - "Freddies", - "Gillespies", - "Goldies", - "Gracies", - "Guthries", - "Hallies", - "Hatties", - "Hetties", - "Hollies", - "Jackies", - "Jamies", - "Janies", - "Jannies", - "Jeanies", - "Jeannies", - "Jennies", - "Jessies", - "Jimmies", - "Jodies", - "Johnies", - "Johnnies", - "Josies", - "Julies", - "Kalgoorlies", - "Kathies", - "Katies", - "Kellies", - "Kewpies", - "Kristies", - "Laramies", - "Lassies", - "Lauries", - "Leslies", - "Lessies", - "Lillies", - "Lizzies", - "Lonnies", - "Lories", - "Lorries", - "Lotties", - "Louies", - "Mackenzies", - "Maggies", - "Maisies", - "Mamies", - "Marcies", - "Margies", - "Maries", - "Marjories", - "Matties", - "McKenzies", - "Melanies", - "Mickies", - "Millies", - "Minnies", - "Mollies", - "Mounties", - "Nannies", - "Natalies", - "Nellies", - "Netties", - "Ollies", - "Ozzies", - "Pearlies", - "Pottawatomies", - "Reggies", - "Richies", - "Rickies", - "Robbies", - "Ronnies", - "Rosalies", - "Rosemaries", - "Rosies", - "Roxies", - "Rushdies", - "Ruthies", - "Sadies", - "Sallies", - "Sammies", - "Scotties", - "Selassies", - "Sherries", - "Sophies", - "Stacies", - "Stefanies", - "Stephanies", - "Stevies", - "Susies", - "Sylvies", - "Tammies", - "Terries", - "Tessies", - "Tommies", - "Tracies", - "Trekkies", - "Valaries", - "Valeries", - "Valkyries", - "Vickies", - "Virgies", - "Willies", - "Winnies", - "Wylies", - "Yorkies", -) - -si_sb_ies_ie = ( - "aeries", - "baggies", - "belies", - "biggies", - "birdies", - "bogies", - "bonnies", - "boogies", - "bookies", - "bourgeoisies", - "brownies", - "budgies", - "caddies", - "calories", - "camaraderies", - "cockamamies", - "collies", - "cookies", - "coolies", - "cooties", - "coteries", - "crappies", - "curies", - "cutesies", - "dogies", - "eyrie", - "floozies", - "footsies", - "freebies", - "genies", - "goalies", - "groupies", - "hies", - "jalousies", - "junkies", - "kiddies", - "laddies", - "lassies", - "lies", - "lingeries", - "magpies", - "menageries", - "mommies", - "movies", - "neckties", - "newbies", - "nighties", - "oldies", - "organdies", - "overlies", - "pies", - "pinkies", - "pixies", - "potpies", - "prairies", - "quickies", - "reveries", - "rookies", - "rotisseries", - "softies", - "sorties", - "species", - "stymies", - "sweeties", - "ties", - "underlies", - "unties", - "veggies", - "vies", - "yuppies", - "zombies", -) - - -si_sb_oes_oe_case = ( - "Chloes", - "Crusoes", - "Defoes", - "Faeroes", - "Ivanhoes", - "Joes", - "McEnroes", - "Moes", - "Monroes", - "Noes", - "Poes", - "Roscoes", - "Tahoes", - "Tippecanoes", - "Zoes", -) - -si_sb_oes_oe = ( - "aloes", - "backhoes", - "canoes", - "does", - "floes", - "foes", - "hoes", - "mistletoes", - "oboes", - "pekoes", - "roes", - "sloes", - "throes", - "tiptoes", - "toes", - "woes", -) - -si_sb_z_zes = ("quartzes", "topazes") - -si_sb_zzes_zz = ("buzzes", "fizzes", "frizzes", "razzes") - -si_sb_ches_che_case = ( - "Andromaches", - "Apaches", - "Blanches", - "Comanches", - "Nietzsches", - "Porsches", - "Roches", -) - -si_sb_ches_che = ( - "aches", - "avalanches", - "backaches", - "bellyaches", - "caches", - "cloches", - "creches", - "douches", - "earaches", - "fiches", - "headaches", - "heartaches", - "microfiches", - "niches", - "pastiches", - "psyches", - "quiches", - "stomachaches", - "toothaches", -) - -si_sb_xes_xe = ("annexes", "axes", "deluxes", "pickaxes") - -si_sb_sses_sse_case = ("Hesses", "Jesses", "Larousses", "Matisses") -si_sb_sses_sse = ( - "bouillabaisses", - "crevasses", - "demitasses", - "impasses", - "mousses", - "posses", -) - -si_sb_ves_ve_case = ( - # *[nwl]ives -> [nwl]live - "Clives", - "Palmolives", -) -si_sb_ves_ve = ( - # *[^d]eaves -> eave - "interweaves", - "weaves", - # *[nwl]ives -> [nwl]live - "olives", - # *[eoa]lves -> [eoa]lve - "bivalves", - "dissolves", - "resolves", - "salves", - "twelves", - "valves", -) - - -plverb_special_s = enclose( - "|".join( - [pl_sb_singular_s] - + pl_sb_uninflected_s - + list(pl_sb_irregular_s.keys()) - + ["(.*[csx])is", "(.*)ceps", "[A-Z].*s"] - ) -) - -pl_sb_postfix_adj = { - "general": ["(?!major|lieutenant|brigadier|adjutant|.*star)\S+"], - "martial": ["court"], -} - -for k in list(pl_sb_postfix_adj.keys()): - pl_sb_postfix_adj[k] = enclose( - enclose("|".join(pl_sb_postfix_adj[k])) + "(?=(?:-|\\s+)%s)" % k - ) - -pl_sb_postfix_adj_stems = "(" + "|".join(list(pl_sb_postfix_adj.values())) + ")(.*)" - - -# PLURAL WORDS ENDING IS es GO TO SINGULAR is - -si_sb_es_is = ( - "amanuenses", - "amniocenteses", - "analyses", - "antitheses", - "apotheoses", - "arterioscleroses", - "atheroscleroses", - "axes", - # 'bases', # bases -> basis - "catalyses", - "catharses", - "chasses", - "cirrhoses", - "cocces", - "crises", - "diagnoses", - "dialyses", - "diereses", - "electrolyses", - "emphases", - "exegeses", - "geneses", - "halitoses", - "hydrolyses", - "hypnoses", - "hypotheses", - "hystereses", - "metamorphoses", - "metastases", - "misdiagnoses", - "mitoses", - "mononucleoses", - "narcoses", - "necroses", - "nemeses", - "neuroses", - "oases", - "osmoses", - "osteoporoses", - "paralyses", - "parentheses", - "parthenogeneses", - "periphrases", - "photosyntheses", - "probosces", - "prognoses", - "prophylaxes", - "prostheses", - "preces", - "psoriases", - "psychoanalyses", - "psychokineses", - "psychoses", - "scleroses", - "scolioses", - "sepses", - "silicoses", - "symbioses", - "synopses", - "syntheses", - "taxes", - "telekineses", - "theses", - "thromboses", - "tuberculoses", - "urinalyses", -) - -pl_prep_list = """ - about above across after among around at athwart before behind - below beneath beside besides between betwixt beyond but by - during except for from in into near of off on onto out over - since till to under until unto upon with""".split() - -pl_prep_list_da = pl_prep_list + ["de", "du", "da"] - -pl_prep_bysize = bysize(pl_prep_list_da) - -pl_prep = enclose("|".join(pl_prep_list_da)) - -pl_sb_prep_dual_compound = ( - r"(.*?)((?:-|\s+)(?:" + pl_prep + r")(?:-|\s+))a(?:-|\s+)(.*)" -) - - -singular_pronoun_genders = set( - [ - "neuter", - "feminine", - "masculine", - "gender-neutral", - "feminine or masculine", - "masculine or feminine", - ] -) - -pl_pron_nom = { - # NOMINATIVE REFLEXIVE - "i": "we", - "myself": "ourselves", - "you": "you", - "yourself": "yourselves", - "she": "they", - "herself": "themselves", - "he": "they", - "himself": "themselves", - "it": "they", - "itself": "themselves", - "they": "they", - "themself": "themselves", - # POSSESSIVE - "mine": "ours", - "yours": "yours", - "hers": "theirs", - "his": "theirs", - "its": "theirs", - "theirs": "theirs", -} - -si_pron = {} -si_pron["nom"] = dict([(v, k) for (k, v) in pl_pron_nom.items()]) -si_pron["nom"]["we"] = "I" - - -pl_pron_acc = { - # ACCUSATIVE REFLEXIVE - "me": "us", - "myself": "ourselves", - "you": "you", - "yourself": "yourselves", - "her": "them", - "herself": "themselves", - "him": "them", - "himself": "themselves", - "it": "them", - "itself": "themselves", - "them": "them", - "themself": "themselves", -} - -pl_pron_acc_keys = enclose("|".join(list(pl_pron_acc.keys()))) -pl_pron_acc_keys_bysize = bysize(list(pl_pron_acc.keys())) - -si_pron["acc"] = dict([(v, k) for (k, v) in pl_pron_acc.items()]) - -for thecase, plur, gend, sing in ( - ("nom", "they", "neuter", "it"), - ("nom", "they", "feminine", "she"), - ("nom", "they", "masculine", "he"), - ("nom", "they", "gender-neutral", "they"), - ("nom", "they", "feminine or masculine", "she or he"), - ("nom", "they", "masculine or feminine", "he or she"), - ("nom", "themselves", "neuter", "itself"), - ("nom", "themselves", "feminine", "herself"), - ("nom", "themselves", "masculine", "himself"), - ("nom", "themselves", "gender-neutral", "themself"), - ("nom", "themselves", "feminine or masculine", "herself or himself"), - ("nom", "themselves", "masculine or feminine", "himself or herself"), - ("nom", "theirs", "neuter", "its"), - ("nom", "theirs", "feminine", "hers"), - ("nom", "theirs", "masculine", "his"), - ("nom", "theirs", "gender-neutral", "theirs"), - ("nom", "theirs", "feminine or masculine", "hers or his"), - ("nom", "theirs", "masculine or feminine", "his or hers"), - ("acc", "them", "neuter", "it"), - ("acc", "them", "feminine", "her"), - ("acc", "them", "masculine", "him"), - ("acc", "them", "gender-neutral", "them"), - ("acc", "them", "feminine or masculine", "her or him"), - ("acc", "them", "masculine or feminine", "him or her"), - ("acc", "themselves", "neuter", "itself"), - ("acc", "themselves", "feminine", "herself"), - ("acc", "themselves", "masculine", "himself"), - ("acc", "themselves", "gender-neutral", "themself"), - ("acc", "themselves", "feminine or masculine", "herself or himself"), - ("acc", "themselves", "masculine or feminine", "himself or herself"), -): - try: - si_pron[thecase][plur][gend] = sing - except TypeError: - si_pron[thecase][plur] = {} - si_pron[thecase][plur][gend] = sing - - -si_pron_acc_keys = enclose("|".join(list(si_pron["acc"].keys()))) -si_pron_acc_keys_bysize = bysize(list(si_pron["acc"].keys())) - - -def get_si_pron(thecase, word, gender): - try: - sing = si_pron[thecase][word] - except KeyError: - raise # not a pronoun - try: - return sing[gender] # has several types due to gender - except TypeError: - return sing # answer independent of gender - - -plverb_irregular_pres = { - # 1st PERS. SING. 2ND PERS. SING. 3RD PERS. SINGULAR - # 3RD PERS. (INDET.) - "am": "are", - "are": "are", - "is": "are", - "was": "were", - "were": "were", - "was": "were", - "have": "have", - "have": "have", - "has": "have", - "do": "do", - "do": "do", - "does": "do", -} - -plverb_ambiguous_pres = { - # 1st PERS. SING. 2ND PERS. SING. 3RD PERS. SINGULAR - # 3RD PERS. (INDET.) - "act": "act", - "act": "act", - "acts": "act", - "blame": "blame", - "blame": "blame", - "blames": "blame", - "can": "can", - "can": "can", - "can": "can", - "must": "must", - "must": "must", - "must": "must", - "fly": "fly", - "fly": "fly", - "flies": "fly", - "copy": "copy", - "copy": "copy", - "copies": "copy", - "drink": "drink", - "drink": "drink", - "drinks": "drink", - "fight": "fight", - "fight": "fight", - "fights": "fight", - "fire": "fire", - "fire": "fire", - "fires": "fire", - "like": "like", - "like": "like", - "likes": "like", - "look": "look", - "look": "look", - "looks": "look", - "make": "make", - "make": "make", - "makes": "make", - "reach": "reach", - "reach": "reach", - "reaches": "reach", - "run": "run", - "run": "run", - "runs": "run", - "sink": "sink", - "sink": "sink", - "sinks": "sink", - "sleep": "sleep", - "sleep": "sleep", - "sleeps": "sleep", - "view": "view", - "view": "view", - "views": "view", -} - -plverb_ambiguous_pres_keys = enclose("|".join(list(plverb_ambiguous_pres.keys()))) - - -plverb_irregular_non_pres = ( - "did", - "had", - "ate", - "made", - "put", - "spent", - "fought", - "sank", - "gave", - "sought", - "shall", - "could", - "ought", - "should", -) - -plverb_ambiguous_non_pres = enclose( - "|".join(("thought", "saw", "bent", "will", "might", "cut")) -) - -# "..oes" -> "..oe" (the rest are "..oes" -> "o") - -pl_v_oes_oe = ("canoes", "floes", "oboes", "roes", "throes", "woes") -pl_v_oes_oe_endings_size4 = ("hoes", "toes") -pl_v_oes_oe_endings_size5 = "shoes" - - -pl_count_zero = ("0", "no", "zero", "nil") - - -pl_count_one = ("1", "a", "an", "one", "each", "every", "this", "that") - -pl_adj_special = {"a": "some", "an": "some", "this": "these", "that": "those"} - -pl_adj_special_keys = enclose("|".join(list(pl_adj_special.keys()))) - -pl_adj_poss = { - "my": "our", - "your": "your", - "its": "their", - "her": "their", - "his": "their", - "their": "their", -} - -pl_adj_poss_keys = enclose("|".join(list(pl_adj_poss.keys()))) - - -# 2. INDEFINITE ARTICLES - -# THIS PATTERN MATCHES STRINGS OF CAPITALS STARTING WITH A "VOWEL-SOUND" -# CONSONANT FOLLOWED BY ANOTHER CONSONANT, AND WHICH ARE NOT LIKELY -# TO BE REAL WORDS (OH, ALL RIGHT THEN, IT'S JUST MAGIC!) - -A_abbrev = r""" -(?! FJO | [HLMNS]Y. | RY[EO] | SQU - | ( F[LR]? | [HL] | MN? | N | RH? | S[CHKLMNPTVW]? | X(YL)?) [AEIOU]) -[FHLMNRSX][A-Z] -""" - -# THIS PATTERN CODES THE BEGINNINGS OF ALL ENGLISH WORDS BEGINING WITH A -# 'y' FOLLOWED BY A CONSONANT. ANY OTHER Y-CONSONANT PREFIX THEREFORE -# IMPLIES AN ABBREVIATION. - -A_y_cons = "y(b[lor]|cl[ea]|fere|gg|p[ios]|rou|tt)" - -# EXCEPTIONS TO EXCEPTIONS - -A_explicit_a = enclose("|".join(("unabomber", "unanimous", "US"))) - -A_explicit_an = enclose( - "|".join(("euler", "hour(?!i)", "heir", "honest", "hono[ur]", "mpeg")) -) - -A_ordinal_an = enclose("|".join(("[aefhilmnorsx]-?th",))) - -A_ordinal_a = enclose("|".join(("[bcdgjkpqtuvwyz]-?th",))) - - -# NUMERICAL INFLECTIONS - -nth = { - 0: "th", - 1: "st", - 2: "nd", - 3: "rd", - 4: "th", - 5: "th", - 6: "th", - 7: "th", - 8: "th", - 9: "th", - 11: "th", - 12: "th", - 13: "th", -} - -ordinal = dict( - ty="tieth", - one="first", - two="second", - three="third", - five="fifth", - eight="eighth", - nine="ninth", - twelve="twelfth", -) - -ordinal_suff = "|".join(list(ordinal.keys())) - - -# NUMBERS - -unit = ["", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine"] -teen = [ - "ten", - "eleven", - "twelve", - "thirteen", - "fourteen", - "fifteen", - "sixteen", - "seventeen", - "eighteen", - "nineteen", -] -ten = [ - "", - "", - "twenty", - "thirty", - "forty", - "fifty", - "sixty", - "seventy", - "eighty", - "ninety", -] -mill = [ - " ", - " thousand", - " million", - " billion", - " trillion", - " quadrillion", - " quintillion", - " sextillion", - " septillion", - " octillion", - " nonillion", - " decillion", -] - - -# SUPPORT CLASSICAL PLURALIZATIONS - -def_classical = dict( - all=False, zero=False, herd=False, names=True, persons=False, ancient=False -) - -all_classical = dict((k, True) for k in list(def_classical.keys())) -no_classical = dict((k, False) for k in list(def_classical.keys())) - - -# TODO: .inflectrc file does not work -# can't just execute methods from another file like this - -# for rcfile in (pathjoin(dirname(__file__), '.inflectrc'), -# expanduser(pathjoin(('~'), '.inflectrc'))): -# if isfile(rcfile): -# try: -# execfile(rcfile) -# except: -# print3("\nBad .inflectrc file (%s):\n" % rcfile) -# raise BadRcFileError - - -class engine: - def __init__(self): - - self.classical_dict = def_classical.copy() - self.persistent_count = None - self.mill_count = 0 - self.pl_sb_user_defined = [] - self.pl_v_user_defined = [] - self.pl_adj_user_defined = [] - self.si_sb_user_defined = [] - self.A_a_user_defined = [] - self.thegender = "neuter" - - deprecated_methods = dict( - pl="plural", - plnoun="plural_noun", - plverb="plural_verb", - pladj="plural_adj", - sinoun="single_noun", - prespart="present_participle", - numwords="number_to_words", - plequal="compare", - plnounequal="compare_nouns", - plverbequal="compare_verbs", - pladjequal="compare_adjs", - wordlist="join", - ) - - def __getattr__(self, meth): - if meth in self.deprecated_methods: - print3("%s() deprecated, use %s()" % (meth, self.deprecated_methods[meth])) - raise DeprecationWarning - raise AttributeError - - def defnoun(self, singular, plural): - """ - Set the noun plural of singular to plural. - - """ - self.checkpat(singular) - self.checkpatplural(plural) - self.pl_sb_user_defined.extend((singular, plural)) - self.si_sb_user_defined.extend((plural, singular)) - return 1 - - def defverb(self, s1, p1, s2, p2, s3, p3): - """ - Set the verb plurals for s1, s2 and s3 to p1, p2 and p3 respectively. - - Where 1, 2 and 3 represent the 1st, 2nd and 3rd person forms of the verb. - - """ - self.checkpat(s1) - self.checkpat(s2) - self.checkpat(s3) - self.checkpatplural(p1) - self.checkpatplural(p2) - self.checkpatplural(p3) - self.pl_v_user_defined.extend((s1, p1, s2, p2, s3, p3)) - return 1 - - def defadj(self, singular, plural): - """ - Set the adjective plural of singular to plural. - - """ - self.checkpat(singular) - self.checkpatplural(plural) - self.pl_adj_user_defined.extend((singular, plural)) - return 1 - - def defa(self, pattern): - """ - Define the indefinate article as 'a' for words matching pattern. - - """ - self.checkpat(pattern) - self.A_a_user_defined.extend((pattern, "a")) - return 1 - - def defan(self, pattern): - """ - Define the indefinate article as 'an' for words matching pattern. - - """ - self.checkpat(pattern) - self.A_a_user_defined.extend((pattern, "an")) - return 1 - - def checkpat(self, pattern): - """ - check for errors in a regex pattern - """ - if pattern is None: - return - try: - match(pattern, "") - except reerror: - print3("\nBad user-defined singular pattern:\n\t%s\n" % pattern) - raise BadUserDefinedPatternError - - def checkpatplural(self, pattern): - """ - check for errors in a regex replace pattern - """ - return - # can't find a pattern that doesn't pass the following test: - # if pattern is None: - # return - # try: - # resub('', pattern, '') - # except reerror: - # print3("\nBad user-defined plural pattern:\n\t%s\n" % pattern) - # raise BadUserDefinedPatternError - - def ud_match(self, word, wordlist): - for i in range(len(wordlist) - 2, -2, -2): # backwards through even elements - mo = search(r"^%s$" % wordlist[i], word, IGNORECASE) - if mo: - if wordlist[i + 1] is None: - return None - pl = resub( - r"\$(\d+)", r"\\1", wordlist[i + 1] - ) # change $n to \n for expand - return mo.expand(pl) - return None - - def classical(self, **kwargs): - """ - turn classical mode on and off for various categories - - turn on all classical modes: - classical() - classical(all=True) - - turn on or off specific claassical modes: - e.g. - classical(herd=True) - classical(names=False) - - By default all classical modes are off except names. - - unknown value in args or key in kwargs rasies exception: UnknownClasicalModeError - - """ - classical_mode = list(def_classical.keys()) - if not kwargs: - self.classical_dict = all_classical.copy() - return - if "all" in kwargs: - if kwargs["all"]: - self.classical_dict = all_classical.copy() - else: - self.classical_dict = no_classical.copy() - - for k, v in list(kwargs.items()): - if k in classical_mode: - self.classical_dict[k] = v - else: - raise UnknownClassicalModeError - - def num(self, count=None, show=None): # (;$count,$show) - """ - Set the number to be used in other method calls. - - Returns count. - - Set show to False to return '' instead. - - """ - if count is not None: - try: - self.persistent_count = int(count) - except ValueError: - raise BadNumValueError - if (show is None) or show: - return str(count) - else: - self.persistent_count = None - return "" - - def gender(self, gender): - """ - set the gender for the singular of plural pronouns - - can be one of: - 'neuter' ('they' -> 'it') - 'feminine' ('they' -> 'she') - 'masculine' ('they' -> 'he') - 'gender-neutral' ('they' -> 'they') - 'feminine or masculine' ('they' -> 'she or he') - 'masculine or feminine' ('they' -> 'he or she') - """ - if gender in singular_pronoun_genders: - self.thegender = gender - else: - raise BadGenderError - - def nummo(self, matchobject): - """ - num but take a matchobject - use groups 1 and 2 in matchobject - """ - return self.num(matchobject.group(1), matchobject.group(2)) - - def plmo(self, matchobject): - """ - plural but take a matchobject - use groups 1 and 3 in matchobject - """ - return self.plural(matchobject.group(1), matchobject.group(3)) - - def plnounmo(self, matchobject): - """ - plural_noun but take a matchobject - use groups 1 and 3 in matchobject - """ - return self.plural_noun(matchobject.group(1), matchobject.group(3)) - - def plverbmo(self, matchobject): - """ - plural_verb but take a matchobject - use groups 1 and 3 in matchobject - """ - return self.plural_verb(matchobject.group(1), matchobject.group(3)) - - def pladjmo(self, matchobject): - """ - plural_adj but take a matchobject - use groups 1 and 3 in matchobject - """ - return self.plural_adj(matchobject.group(1), matchobject.group(3)) - - def sinounmo(self, matchobject): - """ - singular_noun but take a matchobject - use groups 1 and 3 in matchobject - """ - return self.singular_noun(matchobject.group(1), matchobject.group(3)) - - def amo(self, matchobject): - """ - A but take a matchobject - use groups 1 and 3 in matchobject - """ - if matchobject.group(3) is None: - return self.a(matchobject.group(1)) - return self.a(matchobject.group(1), matchobject.group(3)) - - def nomo(self, matchobject): - """ - NO but take a matchobject - use groups 1 and 3 in matchobject - """ - return self.no(matchobject.group(1), matchobject.group(3)) - - def ordinalmo(self, matchobject): - """ - ordinal but take a matchobject - use group 1 - """ - return self.ordinal(matchobject.group(1)) - - def numwordsmo(self, matchobject): - """ - number_to_words but take a matchobject - use group 1 - """ - return self.number_to_words(matchobject.group(1)) - - def prespartmo(self, matchobject): - """ - prespart but take a matchobject - use group 1 - """ - return self.present_participle(matchobject.group(1)) - - # 0. PERFORM GENERAL INFLECTIONS IN A STRING - - def inflect(self, text): - """ - Perform inflections in a string. - - e.g. inflect('The plural of cat is plural(cat)') returns - 'The plural of cat is cats' - - can use plural, plural_noun, plural_verb, plural_adj, singular_noun, a, an, no, ordinal, - number_to_words and prespart - - """ - save_persistent_count = self.persistent_count - sections = splitre(r"(num\([^)]*\))", text) - inflection = [] - - for section in sections: - (section, count) = subn( - r"num\(\s*?(?:([^),]*)(?:,([^)]*))?)?\)", self.nummo, section - ) - if not count: - total = -1 - while total: - (section, total) = subn( - r"(?x)\bplural \( ([^),]*) (, ([^)]*) )? \) ", - self.plmo, - section, - ) - (section, count) = subn( - r"(?x)\bplural_noun \( ([^),]*) (, ([^)]*) )? \) ", - self.plnounmo, - section, - ) - total += count - (section, count) = subn( - r"(?x)\bplural_verb \( ([^),]*) (, ([^)]*) )? \) ", - self.plverbmo, - section, - ) - total += count - (section, count) = subn( - r"(?x)\bplural_adj \( ([^),]*) (, ([^)]*) )? \) ", - self.pladjmo, - section, - ) - total += count - (section, count) = subn( - r"(?x)\bsingular_noun \( ([^),]*) (, ([^)]*) )? \) ", - self.sinounmo, - section, - ) - total += count - (section, count) = subn( - r"(?x)\ban? \( ([^),]*) (, ([^)]*) )? \) ", - self.amo, - section, - ) - total += count - (section, count) = subn( - r"(?x)\bno \( ([^),]*) (, ([^)]*) )? \) ", - self.nomo, - section, - ) - total += count - (section, count) = subn( - r"(?x)\bordinal \( ([^)]*) \) ", - self.ordinalmo, - section, - ) - total += count - (section, count) = subn( - r"(?x)\bnumber_to_words \( ([^)]*) \) ", - self.numwordsmo, - section, - ) - total += count - (section, count) = subn( - r"(?x)\bpresent_participle \( ([^)]*) \) ", - self.prespartmo, - section, - ) - total += count - - inflection.append(section) - - self.persistent_count = save_persistent_count - return "".join(inflection) - - # ## PLURAL SUBROUTINES - - def postprocess(self, orig, inflected): - """ - FIX PEDANTRY AND CAPITALIZATION :-) - """ - if "|" in inflected: - inflected = inflected.split("|")[self.classical_dict["all"]] - if orig == "I": - return inflected - if orig == orig.upper(): - return inflected.upper() - if orig[0] == orig[0].upper(): - return "%s%s" % (inflected[0].upper(), inflected[1:]) - return inflected - - def partition_word(self, text): - mo = search(r"\A(\s*)(.+?)(\s*)\Z", text) - try: - return mo.group(1), mo.group(2), mo.group(3) - except AttributeError: # empty string - return "", "", "" - - # def pl(self, *args, **kwds): - # print 'pl() deprecated, use plural()' - # raise DeprecationWarning - # return self.plural(*args, **kwds) - # - # def plnoun(self, *args, **kwds): - # print 'plnoun() deprecated, use plural_noun()' - # raise DeprecationWarning - # return self.plural_noun(*args, **kwds) - # - # def plverb(self, *args, **kwds): - # print 'plverb() deprecated, use plural_verb()' - # raise DeprecationWarning - # return self.plural_verb(*args, **kwds) - # - # def pladj(self, *args, **kwds): - # print 'pladj() deprecated, use plural_adj()' - # raise DeprecationWarning - # return self.plural_adj(*args, **kwds) - # - # def sinoun(self, *args, **kwds): - # print 'sinoun() deprecated, use singular_noun()' - # raise DeprecationWarning - # return self.singular_noun(*args, **kwds) - # - # def prespart(self, *args, **kwds): - # print 'prespart() deprecated, use present_participle()' - # raise DeprecationWarning - # return self.present_participle(*args, **kwds) - # - # def numwords(self, *args, **kwds): - # print 'numwords() deprecated, use number_to_words()' - # raise DeprecationWarning - # return self.number_to_words(*args, **kwds) - - def plural(self, text, count=None): - """ - Return the plural of text. - - If count supplied, then return text if count is one of: - 1, a, an, one, each, every, this, that - otherwise return the plural. - - Whitespace at the start and end is preserved. - - """ - pre, word, post = self.partition_word(text) - if not word: - return text - plural = self.postprocess( - word, - self._pl_special_adjective(word, count) - or self._pl_special_verb(word, count) - or self._plnoun(word, count), - ) - return "%s%s%s" % (pre, plural, post) - - def plural_noun(self, text, count=None): - """ - Return the plural of text, where text is a noun. - - If count supplied, then return text if count is one of: - 1, a, an, one, each, every, this, that - otherwise return the plural. - - Whitespace at the start and end is preserved. - - """ - pre, word, post = self.partition_word(text) - if not word: - return text - plural = self.postprocess(word, self._plnoun(word, count)) - return "%s%s%s" % (pre, plural, post) - - def plural_verb(self, text, count=None): - """ - Return the plural of text, where text is a verb. - - If count supplied, then return text if count is one of: - 1, a, an, one, each, every, this, that - otherwise return the plural. - - Whitespace at the start and end is preserved. - - """ - pre, word, post = self.partition_word(text) - if not word: - return text - plural = self.postprocess( - word, - self._pl_special_verb(word, count) or self._pl_general_verb(word, count), - ) - return "%s%s%s" % (pre, plural, post) - - def plural_adj(self, text, count=None): - """ - Return the plural of text, where text is an adjective. - - If count supplied, then return text if count is one of: - 1, a, an, one, each, every, this, that - otherwise return the plural. - - Whitespace at the start and end is preserved. - - """ - pre, word, post = self.partition_word(text) - if not word: - return text - plural = self.postprocess(word, self._pl_special_adjective(word, count) or word) - return "%s%s%s" % (pre, plural, post) - - def compare(self, word1, word2): - """ - compare word1 and word2 for equality regardless of plurality - - return values: - eq - the strings are equal - p:s - word1 is the plural of word2 - s:p - word2 is the plural of word1 - p:p - word1 and word2 are two different plural forms of the one word - False - otherwise - - """ - return ( - self._plequal(word1, word2, self.plural_noun) - or self._plequal(word1, word2, self.plural_verb) - or self._plequal(word1, word2, self.plural_adj) - ) - - def compare_nouns(self, word1, word2): - """ - compare word1 and word2 for equality regardless of plurality - word1 and word2 are to be treated as nouns - - return values: - eq - the strings are equal - p:s - word1 is the plural of word2 - s:p - word2 is the plural of word1 - p:p - word1 and word2 are two different plural forms of the one word - False - otherwise - - """ - return self._plequal(word1, word2, self.plural_noun) - - def compare_verbs(self, word1, word2): - """ - compare word1 and word2 for equality regardless of plurality - word1 and word2 are to be treated as verbs - - return values: - eq - the strings are equal - p:s - word1 is the plural of word2 - s:p - word2 is the plural of word1 - p:p - word1 and word2 are two different plural forms of the one word - False - otherwise - - """ - return self._plequal(word1, word2, self.plural_verb) - - def compare_adjs(self, word1, word2): - """ - compare word1 and word2 for equality regardless of plurality - word1 and word2 are to be treated as adjectives - - return values: - eq - the strings are equal - p:s - word1 is the plural of word2 - s:p - word2 is the plural of word1 - p:p - word1 and word2 are two different plural forms of the one word - False - otherwise - - """ - return self._plequal(word1, word2, self.plural_adj) - - def singular_noun(self, text, count=None, gender=None): - """ - Return the singular of text, where text is a plural noun. - - If count supplied, then return the singular if count is one of: - 1, a, an, one, each, every, this, that or if count is None - otherwise return text unchanged. - - Whitespace at the start and end is preserved. - - """ - pre, word, post = self.partition_word(text) - if not word: - return text - sing = self._sinoun(word, count=count, gender=gender) - if sing is not False: - plural = self.postprocess( - word, self._sinoun(word, count=count, gender=gender) - ) - return "%s%s%s" % (pre, plural, post) - return False - - def _plequal(self, word1, word2, pl): - classval = self.classical_dict.copy() - self.classical_dict = all_classical.copy() - if word1 == word2: - return "eq" - if word1 == pl(word2): - return "p:s" - if pl(word1) == word2: - return "s:p" - self.classical_dict = no_classical.copy() - if word1 == pl(word2): - return "p:s" - if pl(word1) == word2: - return "s:p" - self.classical_dict = classval.copy() - - if pl == self.plural or pl == self.plural_noun: - if self._pl_check_plurals_N(word1, word2): - return "p:p" - if self._pl_check_plurals_N(word2, word1): - return "p:p" - if pl == self.plural or pl == self.plural_adj: - if self._pl_check_plurals_adj(word1, word2): - return "p:p" - return False - - def _pl_reg_plurals(self, pair, stems, end1, end2): - if search(r"(%s)(%s\|\1%s|%s\|\1%s)" % (stems, end1, end2, end2, end1), pair): - return True - return False - - def _pl_check_plurals_N(self, word1, word2): - pair = "%s|%s" % (word1, word2) - if pair in list(pl_sb_irregular_s.values()): - return True - if pair in list(pl_sb_irregular.values()): - return True - if pair in list(pl_sb_irregular_caps.values()): - return True - - for (stems, end1, end2) in ( - (pl_sb_C_a_ata, "as", "ata"), - (pl_sb_C_is_ides, "is", "ides"), - (pl_sb_C_a_ae, "s", "e"), - (pl_sb_C_en_ina, "ens", "ina"), - (pl_sb_C_um_a, "ums", "a"), - (pl_sb_C_us_i, "uses", "i"), - (pl_sb_C_on_a, "ons", "a"), - (pl_sb_C_o_i_stems, "os", "i"), - (pl_sb_C_ex_ices, "exes", "ices"), - (pl_sb_C_ix_ices, "ixes", "ices"), - (pl_sb_C_i, "s", "i"), - (pl_sb_C_im, "s", "im"), - (".*eau", "s", "x"), - (".*ieu", "s", "x"), - (".*tri", "xes", "ces"), - (".{2,}[yia]n", "xes", "ges"), - ): - if self._pl_reg_plurals(pair, stems, end1, end2): - return True - return False - - def _pl_check_plurals_adj(self, word1, word2): - # VERSION: tuple in endswith requires python 2.5 - word1a = word1[: word1.rfind("'")] if word1.endswith(("'s", "'")) else "" - word2a = word2[: word2.rfind("'")] if word2.endswith(("'s", "'")) else "" - # TODO: BUG? report upstream. I don't think you should chop off the s' - # word1b = word1[:-2] if word1.endswith("s'") else '' - # word2b = word2[:-2] if word2.endswith("s'") else '' - - # TODO: dresses', dresses's -> dresses, dresses when chop off letters - # then they return False because they are the same. Need to fix this. - - if word1a: - if word2a and ( - self._pl_check_plurals_N(word1a, word2a) - or self._pl_check_plurals_N(word2a, word1a) - ): - return True - # if word2b and ( self._pl_check_plurals_N(word1a, word2b) - # or self._pl_check_plurals_N(word2b, word1a) ): - # return True - - # if word1b: - # if word2a and ( self._pl_check_plurals_N(word1b, word2a) - # or self._pl_check_plurals_N(word2a, word1b) ): - # return True - # if word2b and ( self._pl_check_plurals_N(word1b, word2b) - # or self._pl_check_plurals_N(word2b, word1b) ): - # return True - - return False - - def get_count(self, count=None): - if count is None and self.persistent_count is not None: - count = self.persistent_count - - if count is not None: - count = ( - 1 - if ( - (str(count) in pl_count_one) - or ( - self.classical_dict["zero"] - and str(count).lower() in pl_count_zero - ) - ) - else 2 - ) - else: - count = "" - return count - - # @profile - def _plnoun(self, word, count=None): - count = self.get_count(count) - - # DEFAULT TO PLURAL - - if count == 1: - return word - - # HANDLE USER-DEFINED NOUNS - - value = self.ud_match(word, self.pl_sb_user_defined) - if value is not None: - return value - - # HANDLE EMPTY WORD, SINGULAR COUNT AND UNINFLECTED PLURALS - - if word == "": - return word - - lowerword = word.lower() - - if lowerword in pl_sb_uninflected_complete: - return word - - if word in pl_sb_uninflected_caps: - return word - - for k, v in pl_sb_uninflected_bysize.items(): - if lowerword[-k:] in v: - return word - - if self.classical_dict["herd"] and lowerword in pl_sb_uninflected_herd: - return word - - # HANDLE COMPOUNDS ("Governor General", "mother-in-law", "aide-de-camp", ETC.) - - mo = search(r"^(?:%s)$" % pl_sb_postfix_adj_stems, word, IGNORECASE) - if mo and mo.group(2) != "": - return "%s%s" % (self._plnoun(mo.group(1), 2), mo.group(2)) - - if " a " in lowerword or "-a-" in lowerword: - mo = search(r"^(?:%s)$" % pl_sb_prep_dual_compound, word, IGNORECASE) - if mo and mo.group(2) != "" and mo.group(3) != "": - return "%s%s%s" % ( - self._plnoun(mo.group(1), 2), - mo.group(2), - self._plnoun(mo.group(3)), - ) - - lowersplit = lowerword.split(" ") - if len(lowersplit) >= 3: - for numword in range(1, len(lowersplit) - 1): - if lowersplit[numword] in pl_prep_list_da: - return " ".join( - lowersplit[: numword - 1] - + [self._plnoun(lowersplit[numword - 1], 2)] - + lowersplit[numword:] - ) - - lowersplit = lowerword.split("-") - if len(lowersplit) >= 3: - for numword in range(1, len(lowersplit) - 1): - if lowersplit[numword] in pl_prep_list_da: - return " ".join( - lowersplit[: numword - 1] - + [ - self._plnoun(lowersplit[numword - 1], 2) - + "-" - + lowersplit[numword] - + "-" - ] - ) + " ".join(lowersplit[(numword + 1) :]) - - # HANDLE PRONOUNS - - for k, v in pl_pron_acc_keys_bysize.items(): - if lowerword[-k:] in v: # ends with accusivate pronoun - for pk, pv in pl_prep_bysize.items(): - if lowerword[:pk] in pv: # starts with a prep - if lowerword.split() == [ - lowerword[:pk], - lowerword[-k:], - ]: # only whitespace in between - return lowerword[:-k] + pl_pron_acc[lowerword[-k:]] - - try: - return pl_pron_nom[word.lower()] - except KeyError: - pass - - try: - return pl_pron_acc[word.lower()] - except KeyError: - pass - - # HANDLE ISOLATED IRREGULAR PLURALS - - wordsplit = word.split() - wordlast = wordsplit[-1] - lowerwordlast = wordlast.lower() - - if wordlast in list(pl_sb_irregular_caps.keys()): - llen = len(wordlast) - return "%s%s" % (word[:-llen], pl_sb_irregular_caps[wordlast]) - - if lowerwordlast in list(pl_sb_irregular.keys()): - llen = len(lowerwordlast) - return "%s%s" % (word[:-llen], pl_sb_irregular[lowerwordlast]) - - if (" ".join(wordsplit[-2:])).lower() in list(pl_sb_irregular_compound.keys()): - llen = len( - " ".join(wordsplit[-2:]) - ) # TODO: what if 2 spaces between these words? - return "%s%s" % ( - word[:-llen], - pl_sb_irregular_compound[(" ".join(wordsplit[-2:])).lower()], - ) - - if lowerword[-3:] == "quy": - return word[:-1] + "ies" - - if lowerword[-6:] == "person": - if self.classical_dict["persons"]: - return word + "s" - else: - return word[:-4] + "ople" - - # HANDLE FAMILIES OF IRREGULAR PLURALS - - if lowerword[-3:] == "man": - for k, v in pl_sb_U_man_mans_bysize.items(): - if lowerword[-k:] in v: - return word + "s" - for k, v in pl_sb_U_man_mans_caps_bysize.items(): - if word[-k:] in v: - return word + "s" - return word[:-3] + "men" - if lowerword[-5:] == "mouse": - return word[:-5] + "mice" - if lowerword[-5:] == "louse": - return word[:-5] + "lice" - if lowerword[-5:] == "goose": - return word[:-5] + "geese" - if lowerword[-5:] == "tooth": - return word[:-5] + "teeth" - if lowerword[-4:] == "foot": - return word[:-4] + "feet" - - if lowerword == "die": - return "dice" - - # HANDLE UNASSIMILATED IMPORTS - - if lowerword[-4:] == "ceps": - return word - if lowerword[-4:] == "zoon": - return word[:-2] + "a" - if lowerword[-3:] in ("cis", "sis", "xis"): - return word[:-2] + "es" - - for lastlet, d, numend, post in ( - ("h", pl_sb_U_ch_chs_bysize, None, "s"), - ("x", pl_sb_U_ex_ices_bysize, -2, "ices"), - ("x", pl_sb_U_ix_ices_bysize, -2, "ices"), - ("m", pl_sb_U_um_a_bysize, -2, "a"), - ("s", pl_sb_U_us_i_bysize, -2, "i"), - ("n", pl_sb_U_on_a_bysize, -2, "a"), - ("a", pl_sb_U_a_ae_bysize, None, "e"), - ): - if lowerword[-1] == lastlet: # this test to add speed - for k, v in d.items(): - if lowerword[-k:] in v: - return word[:numend] + post - - # HANDLE INCOMPLETELY ASSIMILATED IMPORTS - - if self.classical_dict["ancient"]: - if lowerword[-4:] == "trix": - return word[:-1] + "ces" - if lowerword[-3:] in ("eau", "ieu"): - return word + "x" - if lowerword[-3:] in ("ynx", "inx", "anx") and len(word) > 4: - return word[:-1] + "ges" - - for lastlet, d, numend, post in ( - ("n", pl_sb_C_en_ina_bysize, -2, "ina"), - ("x", pl_sb_C_ex_ices_bysize, -2, "ices"), - ("x", pl_sb_C_ix_ices_bysize, -2, "ices"), - ("m", pl_sb_C_um_a_bysize, -2, "a"), - ("s", pl_sb_C_us_i_bysize, -2, "i"), - ("s", pl_sb_C_us_us_bysize, None, ""), - ("a", pl_sb_C_a_ae_bysize, None, "e"), - ("a", pl_sb_C_a_ata_bysize, None, "ta"), - ("s", pl_sb_C_is_ides_bysize, -1, "des"), - ("o", pl_sb_C_o_i_bysize, -1, "i"), - ("n", pl_sb_C_on_a_bysize, -2, "a"), - ): - if lowerword[-1] == lastlet: # this test to add speed - for k, v in d.items(): - if lowerword[-k:] in v: - return word[:numend] + post - - for d, numend, post in ( - (pl_sb_C_i_bysize, None, "i"), - (pl_sb_C_im_bysize, None, "im"), - ): - for k, v in d.items(): - if lowerword[-k:] in v: - return word[:numend] + post - - # HANDLE SINGULAR NOUNS ENDING IN ...s OR OTHER SILIBANTS - - if lowerword in pl_sb_singular_s_complete: - return word + "es" - - for k, v in pl_sb_singular_s_bysize.items(): - if lowerword[-k:] in v: - return word + "es" - - if lowerword[-2:] == "es" and word[0] == word[0].upper(): - return word + "es" - - # Wouldn't special words - # ending with 's' always have been caught, regardless of them starting - # with a capital letter (i.e. being names) - # It makes sense below to do this for words ending in 'y' so that - # Sally -> Sallys. But not sure it makes sense here. Where is the case - # of a word ending in s that is caught here and would otherwise have been - # caught below? - # - # removing it as I can't find a case that executes it - # TODO: check this again - # - # if (self.classical_dict['names']): - # mo = search(r"([A-Z].*s)$", word) - # if mo: - # return "%ses" % mo.group(1) - - if lowerword[-1] == "z": - for k, v in pl_sb_z_zes_bysize.items(): - if lowerword[-k:] in v: - return word + "es" - - if lowerword[-2:-1] != "z": - return word + "zes" - - if lowerword[-2:] == "ze": - for k, v in pl_sb_ze_zes_bysize.items(): - if lowerword[-k:] in v: - return word + "s" - - if lowerword[-2:] in ("ch", "sh", "zz", "ss") or lowerword[-1] == "x": - return word + "es" - - # ## (r"(.*)(us)$", "%s%ses"), TODO: why is this commented? - - # HANDLE ...f -> ...ves - - if lowerword[-3:] in ("elf", "alf", "olf"): - return word[:-1] + "ves" - if lowerword[-3:] == "eaf" and lowerword[-4:-3] != "d": - return word[:-1] + "ves" - if lowerword[-4:] in ("nife", "life", "wife"): - return word[:-2] + "ves" - if lowerword[-3:] == "arf": - return word[:-1] + "ves" - - # HANDLE ...y - - if lowerword[-1] == "y": - if lowerword[-2:-1] in "aeiou" or len(word) == 1: - return word + "s" - - if self.classical_dict["names"]: - if lowerword[-1] == "y" and word[0] == word[0].upper(): - return word + "s" - - return word[:-1] + "ies" - - # HANDLE ...o - - if lowerword in pl_sb_U_o_os_complete: - return word + "s" - - for k, v in pl_sb_U_o_os_bysize.items(): - if lowerword[-k:] in v: - return word + "s" - - if lowerword[-2:] in ("ao", "eo", "io", "oo", "uo"): - return word + "s" - - if lowerword[-1] == "o": - return word + "es" - - # OTHERWISE JUST ADD ...s - - return "%ss" % word - - def _pl_special_verb(self, word, count=None): - if self.classical_dict["zero"] and str(count).lower() in pl_count_zero: - return False - count = self.get_count(count) - - if count == 1: - return word - - # HANDLE USER-DEFINED VERBS - - value = self.ud_match(word, self.pl_v_user_defined) - if value is not None: - return value - - # HANDLE IRREGULAR PRESENT TENSE (SIMPLE AND COMPOUND) - - lowerword = word.lower() - try: - firstword = lowerword.split()[0] - except IndexError: - return False # word is '' - - if firstword in list(plverb_irregular_pres.keys()): - return "%s%s" % (plverb_irregular_pres[firstword], word[len(firstword) :]) - - # HANDLE IRREGULAR FUTURE, PRETERITE AND PERFECT TENSES - - if firstword in plverb_irregular_non_pres: - return word - - # HANDLE PRESENT NEGATIONS (SIMPLE AND COMPOUND) - - if firstword.endswith("n't") and firstword[:-3] in list( - plverb_irregular_pres.keys() - ): - return "%sn't%s" % ( - plverb_irregular_pres[firstword[:-3]], - word[len(firstword) :], - ) - - if firstword.endswith("n't"): - return word - - # HANDLE SPECIAL CASES - - mo = search(r"^(%s)$" % plverb_special_s, word) - if mo: - return False - if search(r"\s", word): - return False - if lowerword == "quizzes": - return "quiz" - - # HANDLE STANDARD 3RD PERSON (CHOP THE ...(e)s OFF SINGLE WORDS) - - if ( - lowerword[-4:] in ("ches", "shes", "zzes", "sses") - or lowerword[-3:] == "xes" - ): - return word[:-2] - - # # mo = search(r"^(.*)([cs]h|[x]|zz|ss)es$", - # # word, IGNORECASE) - # # if mo: - # # return "%s%s" % (mo.group(1), mo.group(2)) - - if lowerword[-3:] == "ies" and len(word) > 3: - return lowerword[:-3] + "y" - - if ( - lowerword in pl_v_oes_oe - or lowerword[-4:] in pl_v_oes_oe_endings_size4 - or lowerword[-5:] in pl_v_oes_oe_endings_size5 - ): - return word[:-1] - - if lowerword.endswith("oes") and len(word) > 3: - return lowerword[:-2] - - mo = search(r"^(.*[^s])s$", word, IGNORECASE) - if mo: - return mo.group(1) - - # OTHERWISE, A REGULAR VERB (HANDLE ELSEWHERE) - - return False - - def _pl_general_verb(self, word, count=None): - count = self.get_count(count) - - if count == 1: - return word - - # HANDLE AMBIGUOUS PRESENT TENSES (SIMPLE AND COMPOUND) - - mo = search(r"^(%s)((\s.*)?)$" % plverb_ambiguous_pres_keys, word, IGNORECASE) - if mo: - return "%s%s" % (plverb_ambiguous_pres[mo.group(1).lower()], mo.group(2)) - - # HANDLE AMBIGUOUS PRETERITE AND PERFECT TENSES - - mo = search(r"^(%s)((\s.*)?)$" % plverb_ambiguous_non_pres, word, IGNORECASE) - if mo: - return word - - # OTHERWISE, 1st OR 2ND PERSON IS UNINFLECTED - - return word - - def _pl_special_adjective(self, word, count=None): - count = self.get_count(count) - - if count == 1: - return word - - # HANDLE USER-DEFINED ADJECTIVES - - value = self.ud_match(word, self.pl_adj_user_defined) - if value is not None: - return value - - # HANDLE KNOWN CASES - - mo = search(r"^(%s)$" % pl_adj_special_keys, word, IGNORECASE) - if mo: - return "%s" % (pl_adj_special[mo.group(1).lower()]) - - # HANDLE POSSESSIVES - - mo = search(r"^(%s)$" % pl_adj_poss_keys, word, IGNORECASE) - if mo: - return "%s" % (pl_adj_poss[mo.group(1).lower()]) - - mo = search(r"^(.*)'s?$", word) - if mo: - pl = self.plural_noun(mo.group(1)) - trailing_s = "" if pl[-1] == "s" else "s" - return "%s'%s" % (pl, trailing_s) - - # OTHERWISE, NO IDEA - - return False - - # @profile - def _sinoun(self, word, count=None, gender=None): - count = self.get_count(count) - - # DEFAULT TO PLURAL - - if count == 2: - return word - - # SET THE GENDER - - try: - if gender is None: - gender = self.thegender - elif gender not in singular_pronoun_genders: - raise BadGenderError - except (TypeError, IndexError): - raise BadGenderError - - # HANDLE USER-DEFINED NOUNS - - value = self.ud_match(word, self.si_sb_user_defined) - if value is not None: - return value - - # HANDLE EMPTY WORD, SINGULAR COUNT AND UNINFLECTED PLURALS - - if word == "": - return word - - lowerword = word.lower() - - if word in si_sb_ois_oi_case: - return word[:-1] - - if lowerword in pl_sb_uninflected_complete: - return word - - if word in pl_sb_uninflected_caps: - return word - - for k, v in pl_sb_uninflected_bysize.items(): - if lowerword[-k:] in v: - return word - - if self.classical_dict["herd"] and lowerword in pl_sb_uninflected_herd: - return word - - # HANDLE COMPOUNDS ("Governor General", "mother-in-law", "aide-de-camp", ETC.) - - mo = search(r"^(?:%s)$" % pl_sb_postfix_adj_stems, word, IGNORECASE) - if mo and mo.group(2) != "": - return "%s%s" % (self._sinoun(mo.group(1), 1, gender=gender), mo.group(2)) - - # how to reverse this one? - # mo = search(r"^(?:%s)$" % pl_sb_prep_dual_compound, word, IGNORECASE) - # if mo and mo.group(2) != '' and mo.group(3) != '': - # return "%s%s%s" % (self._sinoun(mo.group(1), 1), - # mo.group(2), - # self._sinoun(mo.group(3), 1)) - - lowersplit = lowerword.split(" ") - if len(lowersplit) >= 3: - for numword in range(1, len(lowersplit) - 1): - if lowersplit[numword] in pl_prep_list_da: - return " ".join( - lowersplit[: numword - 1] - + [self._sinoun(lowersplit[numword - 1], 1, gender=gender)] - + lowersplit[numword:] - ) - - lowersplit = lowerword.split("-") - if len(lowersplit) >= 3: - for numword in range(1, len(lowersplit) - 1): - if lowersplit[numword] in pl_prep_list_da: - return " ".join( - lowersplit[: numword - 1] - + [ - self._sinoun(lowersplit[numword - 1], 1, gender=gender) - + "-" - + lowersplit[numword] - + "-" - ] - ) + " ".join(lowersplit[(numword + 1) :]) - - # HANDLE PRONOUNS - - for k, v in si_pron_acc_keys_bysize.items(): - if lowerword[-k:] in v: # ends with accusivate pronoun - for pk, pv in pl_prep_bysize.items(): - if lowerword[:pk] in pv: # starts with a prep - if lowerword.split() == [ - lowerword[:pk], - lowerword[-k:], - ]: # only whitespace in between - return lowerword[:-k] + get_si_pron( - "acc", lowerword[-k:], gender - ) - - try: - return get_si_pron("nom", word.lower(), gender) - except KeyError: - pass - - try: - return get_si_pron("acc", word.lower(), gender) - except KeyError: - pass - - # HANDLE ISOLATED IRREGULAR PLURALS - - wordsplit = word.split() - wordlast = wordsplit[-1] - lowerwordlast = wordlast.lower() - - if wordlast in list(si_sb_irregular_caps.keys()): - llen = len(wordlast) - return "%s%s" % (word[:-llen], si_sb_irregular_caps[wordlast]) - - if lowerwordlast in list(si_sb_irregular.keys()): - llen = len(lowerwordlast) - return "%s%s" % (word[:-llen], si_sb_irregular[lowerwordlast]) - - if (" ".join(wordsplit[-2:])).lower() in list(si_sb_irregular_compound.keys()): - llen = len( - " ".join(wordsplit[-2:]) - ) # TODO: what if 2 spaces between these words? - return "%s%s" % ( - word[:-llen], - si_sb_irregular_compound[(" ".join(wordsplit[-2:])).lower()], - ) - - if lowerword[-5:] == "quies": - return word[:-3] + "y" - - if lowerword[-7:] == "persons": - return word[:-1] - if lowerword[-6:] == "people": - return word[:-4] + "rson" - - # HANDLE FAMILIES OF IRREGULAR PLURALS - - if lowerword[-4:] == "mans": - for k, v in si_sb_U_man_mans_bysize.items(): - if lowerword[-k:] in v: - return word[:-1] - for k, v in si_sb_U_man_mans_caps_bysize.items(): - if word[-k:] in v: - return word[:-1] - if lowerword[-3:] == "men": - return word[:-3] + "man" - if lowerword[-4:] == "mice": - return word[:-4] + "mouse" - if lowerword[-4:] == "lice": - return word[:-4] + "louse" - if lowerword[-5:] == "geese": - return word[:-5] + "goose" - if lowerword[-5:] == "teeth": - return word[:-5] + "tooth" - if lowerword[-4:] == "feet": - return word[:-4] + "foot" - - if lowerword == "dice": - return "die" - - # HANDLE UNASSIMILATED IMPORTS - - if lowerword[-4:] == "ceps": - return word - if lowerword[-3:] == "zoa": - return word[:-1] + "on" - - for lastlet, d, numend, post in ( - ("s", si_sb_U_ch_chs_bysize, -1, ""), - ("s", si_sb_U_ex_ices_bysize, -4, "ex"), - ("s", si_sb_U_ix_ices_bysize, -4, "ix"), - ("a", si_sb_U_um_a_bysize, -1, "um"), - ("i", si_sb_U_us_i_bysize, -1, "us"), - ("a", si_sb_U_on_a_bysize, -1, "on"), - ("e", si_sb_U_a_ae_bysize, -1, ""), - ): - if lowerword[-1] == lastlet: # this test to add speed - for k, v in d.items(): - if lowerword[-k:] in v: - return word[:numend] + post - - # HANDLE INCOMPLETELY ASSIMILATED IMPORTS - - if self.classical_dict["ancient"]: - - if lowerword[-6:] == "trices": - return word[:-3] + "x" - if lowerword[-4:] in ("eaux", "ieux"): - return word[:-1] - if lowerword[-5:] in ("ynges", "inges", "anges") and len(word) > 6: - return word[:-3] + "x" - - for lastlet, d, numend, post in ( - ("a", si_sb_C_en_ina_bysize, -3, "en"), - ("s", si_sb_C_ex_ices_bysize, -4, "ex"), - ("s", si_sb_C_ix_ices_bysize, -4, "ix"), - ("a", si_sb_C_um_a_bysize, -1, "um"), - ("i", si_sb_C_us_i_bysize, -1, "us"), - ("s", pl_sb_C_us_us_bysize, None, ""), - ("e", si_sb_C_a_ae_bysize, -1, ""), - ("a", si_sb_C_a_ata_bysize, -2, ""), - ("s", si_sb_C_is_ides_bysize, -3, "s"), - ("i", si_sb_C_o_i_bysize, -1, "o"), - ("a", si_sb_C_on_a_bysize, -1, "on"), - ("m", si_sb_C_im_bysize, -2, ""), - ("i", si_sb_C_i_bysize, -1, ""), - ): - if lowerword[-1] == lastlet: # this test to add speed - for k, v in d.items(): - if lowerword[-k:] in v: - return word[:numend] + post - - # HANDLE PLURLS ENDING IN uses -> use - - if ( - lowerword[-6:] == "houses" - or word in si_sb_uses_use_case - or lowerword in si_sb_uses_use - ): - return word[:-1] - - # HANDLE PLURLS ENDING IN ies -> ie - - if word in si_sb_ies_ie_case or lowerword in si_sb_ies_ie: - return word[:-1] - - # HANDLE PLURLS ENDING IN oes -> oe - - if ( - lowerword[-5:] == "shoes" - or word in si_sb_oes_oe_case - or lowerword in si_sb_oes_oe - ): - return word[:-1] - - # HANDLE SINGULAR NOUNS ENDING IN ...s OR OTHER SILIBANTS - - if word in si_sb_sses_sse_case or lowerword in si_sb_sses_sse: - return word[:-1] - - if lowerword in si_sb_singular_s_complete: - return word[:-2] - - for k, v in si_sb_singular_s_bysize.items(): - if lowerword[-k:] in v: - return word[:-2] - - if lowerword[-4:] == "eses" and word[0] == word[0].upper(): - return word[:-2] - - # Wouldn't special words - # ending with 's' always have been caught, regardless of them starting - # with a capital letter (i.e. being names) - # It makes sense below to do this for words ending in 'y' so that - # Sally -> Sallys. But not sure it makes sense here. Where is the case - # of a word ending in s that is caught here and would otherwise have been - # caught below? - # - # removing it as I can't find a case that executes it - # TODO: check this again - # - # if (self.classical_dict['names']): - # mo = search(r"([A-Z].*ses)$", word) - # if mo: - # return "%s" % mo.group(1) - - if lowerword in si_sb_z_zes: - return word[:-2] - - if lowerword in si_sb_zzes_zz: - return word[:-2] - - if lowerword[-4:] == "zzes": - return word[:-3] - - if word in si_sb_ches_che_case or lowerword in si_sb_ches_che: - return word[:-1] - - if lowerword[-4:] in ("ches", "shes"): - return word[:-2] - - if lowerword in si_sb_xes_xe: - return word[:-1] - - if lowerword[-3:] == "xes": - return word[:-2] - # (r"(.*)(us)es$", "%s%s"), TODO: why is this commented? - - # HANDLE ...f -> ...ves - - if word in si_sb_ves_ve_case or lowerword in si_sb_ves_ve: - return word[:-1] - - if lowerword[-3:] == "ves": - if lowerword[-5:-3] in ("el", "al", "ol"): - return word[:-3] + "f" - if lowerword[-5:-3] == "ea" and word[-6:-5] != "d": - return word[:-3] + "f" - if lowerword[-5:-3] in ("ni", "li", "wi"): - return word[:-3] + "fe" - if lowerword[-5:-3] == "ar": - return word[:-3] + "f" - - # HANDLE ...y - - if lowerword[-2:] == "ys": - if len(lowerword) > 2 and lowerword[-3] in "aeiou": - return word[:-1] - - if self.classical_dict["names"]: - if lowerword[-2:] == "ys" and word[0] == word[0].upper(): - return word[:-1] - - if lowerword[-3:] == "ies": - return word[:-3] + "y" - - # HANDLE ...o - - if lowerword[-2:] == "os": - - if lowerword in si_sb_U_o_os_complete: - return word[:-1] - - for k, v in si_sb_U_o_os_bysize.items(): - if lowerword[-k:] in v: - return word[:-1] - - if lowerword[-3:] in ("aos", "eos", "ios", "oos", "uos"): - return word[:-1] - - if lowerword[-3:] == "oes": - return word[:-2] - - # UNASSIMILATED IMPORTS FINAL RULE - - if word in si_sb_es_is: - return word[:-2] + "is" - - # OTHERWISE JUST REMOVE ...s - - if lowerword[-1] == "s": - return word[:-1] - - # COULD NOT FIND SINGULAR - - return False - - # ADJECTIVES - - def a(self, text, count=1): - """ - Return the appropriate indefinite article followed by text. - - The indefinite article is either 'a' or 'an'. - - If count is not one, then return count followed by text - instead of 'a' or 'an'. - - Whitespace at the start and end is preserved. - - """ - mo = search(r"\A(\s*)(?:an?\s+)?(.+?)(\s*)\Z", text, IGNORECASE) - if mo: - word = mo.group(2) - if not word: - return text - pre = mo.group(1) - post = mo.group(3) - result = self._indef_article(word, count) - return "%s%s%s" % (pre, result, post) - return "" - - an = a - - def _indef_article(self, word, count): - mycount = self.get_count(count) - - if mycount != 1: - return "%s %s" % (count, word) - - # HANDLE USER-DEFINED VARIANTS - - value = self.ud_match(word, self.A_a_user_defined) - if value is not None: - return "%s %s" % (value, word) - - # HANDLE ORDINAL FORMS - - for a in ((r"^(%s)" % A_ordinal_a, "a"), (r"^(%s)" % A_ordinal_an, "an")): - mo = search(a[0], word, IGNORECASE) - if mo: - return "%s %s" % (a[1], word) - - # HANDLE SPECIAL CASES - - for a in ( - (r"^(%s)" % A_explicit_an, "an"), - (r"^[aefhilmnorsx]$", "an"), - (r"^[bcdgjkpqtuvwyz]$", "a"), - ): - mo = search(a[0], word, IGNORECASE) - if mo: - return "%s %s" % (a[1], word) - - # HANDLE ABBREVIATIONS - - for a in ( - (r"(%s)" % A_abbrev, "an", VERBOSE), - (r"^[aefhilmnorsx][.-]", "an", IGNORECASE), - (r"^[a-z][.-]", "a", IGNORECASE), - ): - mo = search(a[0], word, a[2]) - if mo: - return "%s %s" % (a[1], word) - - # HANDLE CONSONANTS - - mo = search(r"^[^aeiouy]", word, IGNORECASE) - if mo: - return "a %s" % word - - # HANDLE SPECIAL VOWEL-FORMS - - for a in ( - (r"^e[uw]", "a"), - (r"^onc?e\b", "a"), - (r"^onetime\b", "a"), - (r"^uni([^nmd]|mo)", "a"), - (r"^u[bcfghjkqrst][aeiou]", "a"), - (r"^ukr", "a"), - (r"^(%s)" % A_explicit_a, "a"), - ): - mo = search(a[0], word, IGNORECASE) - if mo: - return "%s %s" % (a[1], word) - - # HANDLE SPECIAL CAPITALS - - mo = search(r"^U[NK][AIEO]?", word) - if mo: - return "a %s" % word - - # HANDLE VOWELS - - mo = search(r"^[aeiou]", word, IGNORECASE) - if mo: - return "an %s" % word - - # HANDLE y... (BEFORE CERTAIN CONSONANTS IMPLIES (UNNATURALIZED) "i.." SOUND) - - mo = search(r"^(%s)" % A_y_cons, word, IGNORECASE) - if mo: - return "an %s" % word - - # OTHERWISE, GUESS "a" - return "a %s" % word - - # 2. TRANSLATE ZERO-QUANTIFIED $word TO "no plural($word)" - - def no(self, text, count=None): - """ - If count is 0, no, zero or nil, return 'no' followed by the plural - of text. - - If count is one of: - 1, a, an, one, each, every, this, that - return count followed by text. - - Otherwise return count follow by the plural of text. - - In the return value count is always followed by a space. - - Whitespace at the start and end is preserved. - - """ - if count is None and self.persistent_count is not None: - count = self.persistent_count - - if count is None: - count = 0 - mo = search(r"\A(\s*)(.+?)(\s*)\Z", text) - pre = mo.group(1) - word = mo.group(2) - post = mo.group(3) - - if str(count).lower() in pl_count_zero: - return "%sno %s%s" % (pre, self.plural(word, 0), post) - else: - return "%s%s %s%s" % (pre, count, self.plural(word, count), post) - - # PARTICIPLES - - def present_participle(self, word): - """ - Return the present participle for word. - - word is the 3rd person singular verb. - - """ - plv = self.plural_verb(word, 2) - - for pat, repl in ( - (r"ie$", r"y"), - (r"ue$", r"u"), # TODO: isn't ue$ -> u encompassed in the following rule? - (r"([auy])e$", r"\g<1>"), - (r"ski$", r"ski"), - (r"[^b]i$", r""), - (r"^(are|were)$", r"be"), - (r"^(had)$", r"hav"), - (r"^(hoe)$", r"\g<1>"), - (r"([^e])e$", r"\g<1>"), - (r"er$", r"er"), - (r"([^aeiou][aeiouy]([bdgmnprst]))$", "\g<1>\g<2>"), - ): - (ans, num) = subn(pat, repl, plv) - if num: - return "%sing" % ans - return "%sing" % ans - - # NUMERICAL INFLECTIONS - - def ordinal(self, num): - """ - Return the ordinal of num. - - num can be an integer or text - - e.g. ordinal(1) returns '1st' - ordinal('one') returns 'first' - - """ - if match(r"\d", str(num)): - try: - num % 2 - n = num - except TypeError: - if "." in str(num): - try: - n = int( - num[-1] - ) # numbers after decimal, so only need last one for ordinal - except ValueError: # ends with '.', so need to use whole string - n = int(num[:-1]) - else: - n = int(num) - try: - post = nth[n % 100] - except KeyError: - post = nth[n % 10] - return "%s%s" % (num, post) - else: - mo = search(r"(%s)\Z" % ordinal_suff, num) - try: - post = ordinal[mo.group(1)] - return resub(r"(%s)\Z" % ordinal_suff, post, num) - except AttributeError: - return "%sth" % num - - def millfn(self, ind=0): - if ind > len(mill) - 1: - print3("number out of range") - raise NumOutOfRangeError - return mill[ind] - - def unitfn(self, units, mindex=0): - return "%s%s" % (unit[units], self.millfn(mindex)) - - def tenfn(self, tens, units, mindex=0): - if tens != 1: - return "%s%s%s%s" % ( - ten[tens], - "-" if tens and units else "", - unit[units], - self.millfn(mindex), - ) - return "%s%s" % (teen[units], mill[mindex]) - - def hundfn(self, hundreds, tens, units, mindex): - if hundreds: - return "%s hundred%s%s%s, " % ( - unit[hundreds], # use unit not unitfn as simpler - " %s " % self.number_args["andword"] if tens or units else "", - self.tenfn(tens, units), - self.millfn(mindex), - ) - if tens or units: - return "%s%s, " % (self.tenfn(tens, units), self.millfn(mindex)) - return "" - - def group1sub(self, mo): - units = int(mo.group(1)) - if units == 1: - return " %s, " % self.number_args["one"] - elif units: - # TODO: bug one and zero are padded with a space but other numbers aren't. check this in perl - return "%s, " % unit[units] - else: - return " %s, " % self.number_args["zero"] - - def group1bsub(self, mo): - units = int(mo.group(1)) - if units: - # TODO: bug one and zero are padded with a space but other numbers aren't. check this in perl - return "%s, " % unit[units] - else: - return " %s, " % self.number_args["zero"] - - def group2sub(self, mo): - tens = int(mo.group(1)) - units = int(mo.group(2)) - if tens: - return "%s, " % self.tenfn(tens, units) - if units: - return " %s %s, " % (self.number_args["zero"], unit[units]) - return " %s %s, " % (self.number_args["zero"], self.number_args["zero"]) - - def group3sub(self, mo): - hundreds = int(mo.group(1)) - tens = int(mo.group(2)) - units = int(mo.group(3)) - if hundreds == 1: - hunword = " %s" % self.number_args["one"] - elif hundreds: - hunword = "%s" % unit[hundreds] - # TODO: bug one and zero are padded with a space but other numbers aren't. check this in perl - else: - hunword = " %s" % self.number_args["zero"] - if tens: - tenword = self.tenfn(tens, units) - elif units: - tenword = " %s %s" % (self.number_args["zero"], unit[units]) - else: - tenword = " %s %s" % (self.number_args["zero"], self.number_args["zero"]) - return "%s %s, " % (hunword, tenword) - - def hundsub(self, mo): - ret = self.hundfn( - int(mo.group(1)), int(mo.group(2)), int(mo.group(3)), self.mill_count - ) - self.mill_count += 1 - return ret - - def tensub(self, mo): - return "%s, " % self.tenfn(int(mo.group(1)), int(mo.group(2)), self.mill_count) - - def unitsub(self, mo): - return "%s, " % self.unitfn(int(mo.group(1)), self.mill_count) - - def enword(self, num, group): - # import pdb - # pdb.set_trace() - - if group == 1: - num = resub(r"(\d)", self.group1sub, num) - elif group == 2: - num = resub(r"(\d)(\d)", self.group2sub, num) - num = resub(r"(\d)", self.group1bsub, num, 1) - # group1bsub same as - # group1sub except it doesn't use the default word for one. - # Is this required? i.e. is the default word not to beused when - # grouping in pairs? - # - # No. This is a bug. Fixed. TODO: report upstream. - elif group == 3: - num = resub(r"(\d)(\d)(\d)", self.group3sub, num) - num = resub(r"(\d)(\d)", self.group2sub, num, 1) - num = resub(r"(\d)", self.group1sub, num, 1) - elif int(num) == 0: - num = self.number_args["zero"] - elif int(num) == 1: - num = self.number_args["one"] - else: - num = num.lstrip().lstrip("0") - self.mill_count = 0 - # surely there's a better way to do the next bit - mo = search(r"(\d)(\d)(\d)(?=\D*\Z)", num) - while mo: - num = resub(r"(\d)(\d)(\d)(?=\D*\Z)", self.hundsub, num, 1) - mo = search(r"(\d)(\d)(\d)(?=\D*\Z)", num) - num = resub(r"(\d)(\d)(?=\D*\Z)", self.tensub, num, 1) - num = resub(r"(\d)(?=\D*\Z)", self.unitsub, num, 1) - return num - - def blankfn(self, mo): - """ do a global blank replace - TODO: surely this can be done with an option to resub - rather than this fn - """ - return "" - - def commafn(self, mo): - """ do a global ',' replace - TODO: surely this can be done with an option to resub - rather than this fn - """ - return "," - - def spacefn(self, mo): - """ do a global ' ' replace - TODO: surely this can be done with an option to resub - rather than this fn - """ - return " " - - def number_to_words( - self, - num, - wantlist=False, - group=0, - comma=",", - andword="and", - zero="zero", - one="one", - decimal="point", - threshold=None, - ): - """ - Return a number in words. - - group = 1, 2 or 3 to group numbers before turning into words - comma: define comma - andword: word for 'and'. Can be set to ''. - e.g. "one hundred and one" vs "one hundred one" - zero: word for '0' - one: word for '1' - decimal: word for decimal point - threshold: numbers above threshold not turned into words - - parameters not remembered from last call. Departure from Perl version. - """ - self.number_args = dict(andword=andword, zero=zero, one=one) - num = "%s" % num - - # Handle "stylistic" conversions (up to a given threshold)... - if threshold is not None and float(num) > threshold: - spnum = num.split(".", 1) - while comma: - (spnum[0], n) = subn(r"(\d)(\d{3}(?:,|\Z))", r"\1,\2", spnum[0]) - if n == 0: - break - try: - return "%s.%s" % (spnum[0], spnum[1]) - except IndexError: - return "%s" % spnum[0] - - if group < 0 or group > 3: - raise BadChunkingOptionError - nowhite = num.lstrip() - if nowhite[0] == "+": - sign = "plus" - elif nowhite[0] == "-": - sign = "minus" - else: - sign = "" - - myord = num[-2:] in ("st", "nd", "rd", "th") - if myord: - num = num[:-2] - finalpoint = False - if decimal: - if group != 0: - chunks = num.split(".") - else: - chunks = num.split(".", 1) - if chunks[-1] == "": # remove blank string if nothing after decimal - chunks = chunks[:-1] - finalpoint = True # add 'point' to end of output - else: - chunks = [num] - - first = 1 - loopstart = 0 - - if chunks[0] == "": - first = 0 - if len(chunks) > 1: - loopstart = 1 - - for i in range(loopstart, len(chunks)): - chunk = chunks[i] - # remove all non numeric \D - chunk = resub(r"\D", self.blankfn, chunk) - if chunk == "": - chunk = "0" - - if group == 0 and (first == 0 or first == ""): - chunk = self.enword(chunk, 1) - else: - chunk = self.enword(chunk, group) - - if chunk[-2:] == ", ": - chunk = chunk[:-2] - chunk = resub(r"\s+,", self.commafn, chunk) - - if group == 0 and first: - chunk = resub(r", (\S+)\s+\Z", " %s \\1" % andword, chunk) - chunk = resub(r"\s+", self.spacefn, chunk) - # chunk = resub(r"(\A\s|\s\Z)", self.blankfn, chunk) - chunk = chunk.strip() - if first: - first = "" - chunks[i] = chunk - - numchunks = [] - if first != 0: - numchunks = chunks[0].split("%s " % comma) - - if myord and numchunks: - # TODO: can this be just one re as it is in perl? - mo = search(r"(%s)\Z" % ordinal_suff, numchunks[-1]) - if mo: - numchunks[-1] = resub( - r"(%s)\Z" % ordinal_suff, ordinal[mo.group(1)], numchunks[-1] - ) - else: - numchunks[-1] += "th" - - for chunk in chunks[1:]: - numchunks.append(decimal) - numchunks.extend(chunk.split("%s " % comma)) - - if finalpoint: - numchunks.append(decimal) - - # wantlist: Perl list context. can explictly specify in Python - if wantlist: - if sign: - numchunks = [sign] + numchunks - return numchunks - elif group: - signout = "%s " % sign if sign else "" - return "%s%s" % (signout, ", ".join(numchunks)) - else: - signout = "%s " % sign if sign else "" - num = "%s%s" % (signout, numchunks.pop(0)) - if decimal is None: - first = True - else: - first = not num.endswith(decimal) - for nc in numchunks: - if nc == decimal: - num += " %s" % nc - first = 0 - elif first: - num += "%s %s" % (comma, nc) - else: - num += " %s" % nc - return num - - # Join words with commas and a trailing 'and' (when appropriate)... - - def join( - self, - words, - sep=None, - sep_spaced=True, - final_sep=None, - conj="and", - conj_spaced=True, - ): - """ - Join words into a list. - - e.g. join(['ant', 'bee', 'fly']) returns 'ant, bee, and fly' - - options: - conj: replacement for 'and' - sep: separator. default ',', unless ',' is in the list then ';' - final_sep: final separator. default ',', unless ',' is in the list then ';' - conj_spaced: boolean. Should conj have spaces around it - - """ - if not words: - return "" - if len(words) == 1: - return words[0] - - if conj_spaced: - if conj == "": - conj = " " - else: - conj = " %s " % conj - - if len(words) == 2: - return "%s%s%s" % (words[0], conj, words[1]) - - if sep is None: - if "," in "".join(words): - sep = ";" - else: - sep = "," - if final_sep is None: - final_sep = sep - - final_sep = "%s%s" % (final_sep, conj) - - if sep_spaced: - sep += " " - - return "%s%s%s" % (sep.join(words[0:-1]), final_sep, words[-1]) diff --git a/Code/irc/inflect.pyc b/Code/irc/inflect.pyc deleted file mode 100644 index 62e9932..0000000 Binary files a/Code/irc/inflect.pyc and /dev/null differ diff --git a/Code/irc/mentions.pyc b/Code/irc/mentions.pyc deleted file mode 100644 index e452a1d..0000000 Binary files a/Code/irc/mentions.pyc and /dev/null differ diff --git a/Code/irc/newBanter.py b/Code/irc/newBanter.py deleted file mode 100644 index d8b91c7..0000000 --- a/Code/irc/newBanter.py +++ /dev/null @@ -1,55 +0,0 @@ -#!/usr/bin/python3 -import random -import re - -dictDir = "/usr/share/dict/" - -def getBanter(morphWord="bant", dictName="words"): - with open(dictDir + dictName, "r") as dict: - # get rid of all the words with apostrophes - words = list(filter(lambda word: re.search(r"^[^']*$", word), dict.readlines())) - - head = getBanterHead(words, morphWord) - tail = getBanterTail(words, morphWord) - - if head == "" and tail == "": - return "" # dang, we just failed - else: - # pick randomly between non-empty strings - return random.choice([w for w in [head, tail] if w != ""]) - -def getBanterHead(words, morphWord): - morphHead = morphWord[0:-1] - morphLast = morphWord[-1] - - filtered = list(filter(lambda word: re.search(morphHead, word), words)) - if len(filtered) == 0: - return "" # nothing applicable found - - word = random.choice(filtered).strip("\n") - end = word.find(morphHead) + len(morphHead) - if end == len(word): - return word + morphLast - else: - if "aeiou".find(word[end]) > -1: # just append 't' - return word[:end] + morphLast + word[end:] - else: # replace the letter with 'b' - return word[:end] + morphLast + word[end + 1 :] - -def getBanterTail(words, morphWord): - morphTail = morphWord[1:] - morphFirst = morphWord[0] - - filtered = list(filter(lambda word: re.search(morphTail, word), words)) - if len(filtered) == 0: - return "" # nothing applicable found - - word = random.choice(filtered).strip("\n") - start = word.find(morphTail) - if start == 0: - return morphFirst + word - else: - if "aeiou".find(word[start]) > -1: # just append a 'b' - return word[:start] + morphFirst + word[start:] - else: # replace the letter with 'b' - return word[: start - 1] + morphFirst + word[start:] diff --git a/Code/irc/pretty_date.pyc b/Code/irc/pretty_date.pyc deleted file mode 100644 index e362852..0000000 Binary files a/Code/irc/pretty_date.pyc and /dev/null differ diff --git a/Code/irc/puzzle.py b/Code/irc/puzzle.py deleted file mode 100644 index 9a43c98..0000000 --- a/Code/irc/puzzle.py +++ /dev/null @@ -1,185 +0,0 @@ -#!/usr/bin/python -import random -import hashlib -import inflect -import quote_puzzle -import dict_puzzle -import textcaptcha - -p = inflect.engine() -primes = [11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71] -fuzz_amount = 3 - - -def make_puzzle(obfuscate=True, roll=None): - answer = 0 - bonus = 0 - puzzle = random.choice( - [ - "Prove you're not a robot: ", - "Are you a robot?: ", - "Anti-bot check: ", - "Counter-cnd0rphant measures: ", - "Cosn0k countermeasures: ", - "Anti-tilde7hief precautions: ", - "Pro-l0gin challenge: ", - "Riddle me this: ", - "Would you like to play a game? ", - "How about this? " - ] - ) - puzzle += random.choice( - [ - "What is", - "What do you get from", - "What do you get with", - "What is the value of", - "Can you answer", - "Can you tell me", - "Ask wiz3bot what is", - "Does anybody know", - "Who knows", - "Guess what", - "Calculate", - "Find out" - ] - ) - puzzle += " " - roll = roll or random.randrange(0, 21) - var1 = random.randrange(1, 10) - var2 = random.randrange(1, 10) - var3 = random.randrange(1, 20) - var4 = random.randrange(1, 20) - let1_ord = random.randrange(ord("a"), ord("z") + 1) - - if roll == 0: - answer = var1 + var2 - puzzle += "{} {} {}".format( - p.number_to_words(var1), - random.choice(["and", "plus", "sum", "add"]), - p.number_to_words(var2), - ) - - elif roll == 1: - answer = var1 * var2 - puzzle += "{} {} {}".format( - p.number_to_words(var1), - random.choice(["times", "multiply", "multiplied by", "product"]), - p.number_to_words(var2), - ) - - elif roll == 2: - if var2 > var1: - var1, var2 = var2, var1 - answer = var1 - var2 - puzzle += "{} {} {}".format( - p.number_to_words(var1), - random.choice(["minus", "subtract", "take away", "less"]), - p.number_to_words(var2), - ) - - elif roll == 3: - if var2 > var1: - var1, var2 = var2, var1 - answer = var1 * 2 / var2 - puzzle += "{} {} {} (no remainder)".format( - p.number_to_words(var1 * 2), - random.choice(["divided by", "over"]), - p.number_to_words(var2), - ) - - elif roll == 4: - answer = var1 ** var2 - puzzle += "{} to the {} power".format( - p.number_to_words(var1), p.ordinal(p.number_to_words(var2)) - ) - - elif roll == 5: - p1 = random.choice(primes) - p2 = random.choice(primes) - - def answer(guess): - # Check the the numbers entered are correct, regardless of order - # or surrounding whitespace. - attempt = sorted(word.strip() for word in guess.split(",")) - correct = sorted([str(p1), str(p2)]) - return attempt == correct - - bonus = 1 - puzzle += "{} when factored into its two primes (answer in the form of the two primes with a comma between)".format( - p.number_to_words(p1 * p2) - ) - - elif roll == 6: - prime = random.choice(primes) - answer = prime % var1 - puzzle += p.number_to_words(prime) + " modulus " + p.number_to_words(var1) - elif roll == 7: - if let1_ord + var1 > ord("z"): - let1_ord -= var1 - answer = chr(let1_ord + var1) - puzzle += "letter comes {} letters after '{}'".format( - p.number_to_words(var1), chr(let1_ord) - ) - - obfuscate = False - elif roll == 8: - if let1_ord - var1 < ord("a"): - let1_ord += var1 - answer = chr(let1_ord - var1) - puzzle += "letter comes {} letters before '{}'".format( - p.number_to_words(var1), chr(let1_ord) - ) - - obfuscate = False - elif roll == 9: - answer, puzzle = quote_puzzle.get_quote() - obfuscate = False - elif roll == 10: - answer = str(min(var1, var2, var3, var4)) - puzzle += "the {} of {}, {}, {}, and {}".format( - random.choice(["smallest", "lowest"]), - p.number_to_words(var1), - p.number_to_words(var2), - p.number_to_words(var3), - p.number_to_words(var4), - ) - - elif roll == 11: - answer = str(max(var1, var2, var3, var4)) - puzzle += "the {} of {}, {}, {}, and {}".format( - random.choice(["biggest", "largest"]), - p.number_to_words(var1), - p.number_to_words(var2), - p.number_to_words(var3), - p.number_to_words(var4), - ) - - elif roll <= 14: # 12-14 - answer, puzzle = dict_puzzle.get_puzzle() - obfuscate = False - elif roll <= 17: # 15-17 - answer, puzzle = dict_puzzle.get_anagram() - obfuscate = False - elif roll == 18: - answer, puzzle = quote_puzzle.get_chuck() - obfuscate = False - elif roll <= 20: #19-20 - captcha = textcaptcha.get_captcha() - puzzle = captcha['q'] # the question part of the captcha - print(captcha) - answer = lambda a : hashlib.md5(a.encode()).hexdigest() in captcha['a'] # check if the answer is correct - obfuscate = False - bonus = 1 - - # Add a question mark on the end of the question - if puzzle[-1] != "?": - puzzle += "?" - - if obfuscate == True: - for _ in range(fuzz_amount): - idx = random.randrange(len(puzzle) - 2) # get between 0 and string length (except the ? mark) - puzzle = "".join( - [puzzle[0:idx], chr(random.randint(33, 126)), puzzle[idx + 1 :]] - ) - return [puzzle, answer, bonus] diff --git a/Code/irc/quote_puzzle.py b/Code/irc/quote_puzzle.py deleted file mode 100644 index f755e52..0000000 --- a/Code/irc/quote_puzzle.py +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/python - -import json -import urllib -import random -import re - -quotefile = "/home/karlen/irc/quotes.txt" -chuckfile = "chuck.txt" -chuckApi = "https://api.icndb.com/jokes/random" - -def get_quote(): - quotes = open(quotefile, "r").read().split("---") - quote, attr = random.choice(quotes).strip().splitlines() - quote = quote[:200] # get only the first 200 chars - word = random.choice([q for q in quote.split(" ") if len(q) > 1]) - quote = quote.replace(word, re.sub(r"[a-zA-Z]", "_", word)) - return [word, 'Fill in the blank: "' + quote + '" ' + attr] - -def get_chuck(): - #chucks = open(chuckfile, "r").readlines() - #chuck = random.choice(chucks).rstrip()[:200] # get only the first 200 chars - # ha ha! let's see if we can confus login - chuck = json.loads(urllib.urlopen(chuckApi).read().decode())['value']['joke'][:200] - word = random.choice([w for w in chuck.split(" ") if len(w) > 1 and w.lower() != "chuck" and w.lower() != "norris"]) - chuck = chuck.replace(word, re.sub(r"[a-zA-Z]", "_", word)).replace(""", "\"") - return [word, 'Fill in the blank: "{}"'.format(chuck)] diff --git a/Code/irc/rhymesWith.py b/Code/irc/rhymesWith.py deleted file mode 100644 index ce6d10e..0000000 --- a/Code/irc/rhymesWith.py +++ /dev/null @@ -1,40 +0,0 @@ -#!/usr/bin/python3 -import urllib - -# from lxml.html import fromstring -from bs4 import BeautifulSoup -import random - - -def getRhymes(word): - words = [] - url = "http://www.rhymer.com/RhymingDictionaryLast/%s.html" % word - soup = BeautifulSoup(urllib.request.urlopen(url).read(), "html.parser") - - for t in soup.find_all("table", "table"): - words.append( - random.choice( - [ - w - for w in t.text.split("\n") - if w not in [u"", u"\xa0"] and "-" not in w - ] - ) - ) - return words - - -def rhymeZone(word): - words = [] - url = ( - "http://rhymezone.com/r/rhyme.cgi?Word=%s&typeofrhyme=perfect&org1=syl&org2=l&org3=y" - % word - ) - soup = BeautifulSoup(urllib.request.urlopen(url).read(), "html.parser") - - for t in soup.find_all("a", "d"): - w = t.text.rstrip() - if w not in [u"", u"\xa0"] and "?" not in t: - words.append(w) - random.shuffle(words) - return words[0:5] diff --git a/Code/irc/run.sh b/Code/irc/run.sh deleted file mode 100755 index dc98a46..0000000 --- a/Code/irc/run.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -nohup ./tilde_bot.py -s 127.0.0.1 -n tilde_bot -c \#bot_test >> log 2>> log & diff --git a/Code/irc/run_banter.sh b/Code/irc/run_banter.sh index 7bd4253..2b52756 100755 --- a/Code/irc/run_banter.sh +++ b/Code/irc/run_banter.sh @@ -1,9 +1,9 @@ #!/bin/bash - -if [[ ! `pidof -sx banterbot.py` ]]; then - #nohup ./banterbot.py -s 127.0.0.1:6667 -n banterbot -c \#tildetown \#bots >> banterlog 2>> banterlog & +# check if the bot is already running +if [[ ! `pidof -sx bot_launcher.py` || ! `ps -p $(pidof -sx bot_launcher.py) -o args | grep "\-n banterbot"` ]]; then echo "Starting banterbot" - nohup ./banterbot.py -s 127.0.0.1:6667 -n banterbot -c \#tildetown \#bots >> banterlog 2>> banterlog & + /home/krowbar/Code/irc/bot_launcher.py -n banterbot -s 127.0.0.1 -p 6667 -c \#tildetown \#bots + # nohup /home/krowbar/Code/irc/bot_launcher.py -n banterbot -s 127.0.0.1:6667 -c \#bot_test else echo "Banterbot has already been started" fi diff --git a/Code/irc/run_madlib.sh b/Code/irc/run_madlib.sh deleted file mode 100755 index 0fd18db..0000000 --- a/Code/irc/run_madlib.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash - -if [[ ! `pidof -sx madlibbot.py` ]]; then - nohup ./madlibbot/madlibbot.py -s 127.0.0.1:6667 -n madlibbot -c \#bots \#madlibs >> madliblog 2>> madliblog & - echo "Starting madlibbot" -else - echo "madlibbot has already been started" -fi diff --git a/Code/irc/run_tilde.sh b/Code/irc/run_tilde.sh index da66d45..8dc0a26 100755 --- a/Code/irc/run_tilde.sh +++ b/Code/irc/run_tilde.sh @@ -1,8 +1,9 @@ #!/bin/bash -if [[ ! `pidof -sx tildebot.py` ]]; then +# check if the bot is already running +if [[ ! `pidof -sx bot_launcher.py` || ! `ps -p $(pidof -sx bot_launcher.py) -o args | grep "\-n tildebot"` ]]; then echo "Starting tildebot" - nohup ./tildebot.py -s 127.0.0.1:6667 -n tildebot -c \#tildetown \#bots >> tildelog 2>> tildelog & - #nohup ./tildebot.py -s 127.0.0.1:6667 -n tildebot -c \#bots >> tildelog 2>> tildelog & + /home/krowbar/Code/irc/bot_launcher.py -n tildebot -s 127.0.0.1 -p 6667 -c \#bots + # nohup /home/krowbar/Code/irc/bot_launcher.py -n tildebot -s 127.0.0.1:6667 -c \#bot_test else echo "Tildebot has already been started" fi diff --git a/Code/irc/run_topic.sh b/Code/irc/run_topic.sh deleted file mode 100755 index 3a619c5..0000000 --- a/Code/irc/run_topic.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/bash -if [[ ! `pidof -sx topicbot.py` ]]; then - nohup ./topicbot.py -s 127.0.0.1:6667 -n topicbot -c \#tildetown \#bots >> topiclog 2>> topiclog & -fi -#nohup ./topicbot.py -s 127.0.0.1:6667 -n topicbot -c \#bot_test \#bots >> topiclog 2>> topiclog & -#./topic_bot.py -s 127.0.0.1 -n topic_bot -c \#bot_test diff --git a/Code/irc/run_wang.sh b/Code/irc/run_wang.sh deleted file mode 100755 index 6dd82ac..0000000 --- a/Code/irc/run_wang.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash - -nohup ./wangbot.py -n numberwang_bot -c \#bots >> wanglog 2>> wanglog & -#nohup ./wangbot.py -s 127.0.0.1 -n numberwang_bot -c \#bot_test >> wanglog 2>> wanglog & diff --git a/Code/irc/tildebot.py b/Code/irc/tildebot.py deleted file mode 100755 index 497c1ab..0000000 --- a/Code/irc/tildebot.py +++ /dev/null @@ -1,394 +0,0 @@ -#!/usr/bin/python -# http://wiki.shellium.org/w/Writing_an_IRC_bot_in_Python - -# Import some necessary libraries. -import socket -import os -import sys -import time -import argparse -import fileinput -import random - -import inflect -import puzzle -import util - -parser = argparse.ArgumentParser() - -parser.add_argument( - "-s", - "--server", - dest="server", - default="127.0.0.1:6667", - help="the server to connect to", - metavar="SERVER", -) -parser.add_argument( - "-c", - "--channels", - dest="channels", - nargs="+", - default=["#bot_test"], - help="the channels to join", - metavar="CHANNELS", -) -parser.add_argument( - "-n", - "--nick", - dest="nick", - default="tildebot", - help="the nick to use", - metavar="NICK", -) - -args = parser.parse_args() - -p = inflect.engine() -challenges = {} -SCORE_FILE = "tildescores.txt" -JACKPOT_FILE = "tildejackpot.txt" -JACKPOT_MIN = 3 -DEBUG = False - - -def too_recent(time1, time2): - return int(time1) - int(time2) < 60 * 60 - - -def get_positive(): - return random.choice( - [ - "Yes", - "Yep", - "Yeppers", - "Correct", - "You got it", - "Yeah", - "Right on", - "Uh-huh", - "Positive", - "Totally right", - "Close enough", - "That's it", - "Winner, winner", - "Bingo", - "Affirmative", - ] - ) - - -def get_negative(): - return random.choice( - [ - "No", - "Nope", - "Sorry", - "Wrong", - "Nuh-uh", - "Negatory", - "Incorrect", - "Not today", - "Try again", - "Maybe later", - "Maybe next time", - "Probably not", - "Answer hazy", - "Not quite", - "Not even close", - "Not for you", - "I think not" - ] - ) - - -def get_superlative(score): - if score > 4: - return random.choice( - [ - "super cool", - "totally rad", - "extraordinary", - "dynomite", - "#topdrawer", - "a #TopLad", - "the cat's meow", - "a tilde town hero", - "my favorite person", - "incredibly lucky", - "unbelievable", - "a tilde town hunk", - "could bring all the boys to the yard", - "worth twice their weight in gold", - "the hero we need", - "no ordinary townie", - ] - ) - elif score > 2: - return random.choice( - [ - "really cool", - "pretty neat", - "rather nice", - "a dynamic doggo", - "radical", - "intense", - "pretty lucky", - "knows the territory", - "has what it takes", - "has mad skillz", - "going the distance", - "a hard worker", - "my sunshine", - "ready to rumble", - ] - ) - else: - return random.choice( - [ - "cool", - "nice", - "acceptible", - "good enough", - "a promising pupper", - "better than a horse", - "swell", - "a little lucky", - "just credible", - "my friend", - "probably not a robot", - "valuable to the team", - "now trending", - ] - ) - - -def get_bad_thing(): - return random.choice( - [ - "is a meanie", - "mugs me right off", - "miffed me off", - "is worse than a horse", - "smells like a ghost", - "probably didn't bathe today", - "probably shakes babies", - "didn't guess hard enough", - "isn't lucky", - "smells of elderberries", - "should reconsider their life choices", - "did't believe in the heart of the tilde", - "came to the wrong side of town", - "should have stopped while they were ahead", - "requires annotations from an authoratative source", - "could have been a contender", - "spreads vicious rumors", - "drank my milkshake", - "is probably cheating", - "is trying too hard", - "didn't really try", - "should try harder", - "caught me in a bad mood", - "should have gone with their first choice", - "did not receive IFR clearance from tower", - "was tardy for class", - "is on double secret probation", - "forgot their keys", - "forgot to bribe me", - "forgot to close the door", - "waited too long", - "doesn't call me on my cellphone", - "isn't wearing a seatbelt", - "didn't courtesy flush", - "asked a bot for answers", - "was right but I didn't feel like it", - "is right on opposite day", - "actually answered the last question", - "has their pants on backwards", - "forgot their own name", - ] - ) - - -def get_prize(name, isHuman, bonus=0): - prizes = [1] * 8 + [2] * 4 + [3] * 2 + [5] * isHuman # no 5pt prize for non-humans - prize = random.choice(prizes) + bonus - if ( - random.randint(1, 10) > 6 - 4 * isHuman - ): # 80% of the time it's a normal prize (40% for not humans) - return [ - prize, - "{}: {}! You are {} and get {} tildes!".format( - name, - (get_positive() if isHuman else get_negative()), - get_superlative(prize), - p.number_to_words(prize), - ), - ] - else: # 20% of the time its a jackpot situation - with open(JACKPOT_FILE, "r+") as jackpotfile: - jackpot = int(jackpotfile.readline().strip("\n")) - jackpotfile.seek(0) - jackpotfile.truncate() - if ( - random.randint(1, 10) > 1 or not isHuman - ): # 90% of the time it's a non-prize. non-humans never win jackpot - new_jackpot = jackpot + max(1, prize) - jackpotfile.write( - str(new_jackpot) - ) # increase the jackpot by the prize size - return [ - 0, - "{} {} and gets no tildes! (Jackpot is now {} tildes)".format( - name, get_bad_thing(), new_jackpot - ), - ] - else: # hit jackpot! - jackpotfile.write(str(JACKPOT_MIN)) - return [ - jackpot, - "{} hit the jackpot and won **{}** tildes!".format( - name, p.number_to_words(jackpot) - ), - ] - - -def show_jackpot(channel): - with open(JACKPOT_FILE, "r") as jackpotfile: - jackpot = int(jackpotfile.readline().strip("\n")) - util.sendmsg( - ircsock, - channel, - "The jackpot is currently {} tildes!".format(p.number_to_words(jackpot)), - ) - - -def give_tilde(channel, user, name, time, human, bonus=0): - found = False - with open(SCORE_FILE, "r+") as scorefile: - scores = scorefile.readlines() - scorefile.seek(0) - scorefile.truncate() - for score in scores: - name, score_on_file, timestamp = score.strip("\n").split("&^%") - if name == user: - found = True - if too_recent(time, timestamp) and not DEBUG: - util.sendmsg( - ircsock, - channel, - "{} asked for a tilde too recently and {}. Try again later.".format( - name, get_bad_thing() - ), - ) - else: - prizevalue, prizetext = get_prize(name, human, bonus) - score = "{}&^%{}&^%{}\n".format( - name, str(int(score_on_file) + prizevalue), time - ) - util.sendmsg(ircsock, channel, prizetext) - scorefile.write(score) - if not found: - prizevalue, prizetext = get_prize(name, True, bonus) - util.sendmsg( - ircsock, - channel, - "Welcome to the tilde game! Here's {} free tildes to start you off.".format( - p.number_to_words(prizevalue + 1) - ), - ) - scorefile.write("{}&^%{}&^%{}\n".format(user, str(prizevalue + 1), time)) - - -def show_tildescore(channel, user, name): - with open(SCORE_FILE, "r") as scorefile: - for _idx, score in enumerate(scorefile): - person = score.strip("\n").split("&^%") - if person[0] == user: - util.sendmsg( - ircsock, - channel, - "{} has {} tildes!".format(name, p.number_to_words(person[1])), - ) - return - # person has not played yet - util.sendmsg(ircsock, channel, "{} has no tildes yet!".format(name)) - - -def challenge(channel, user, name, time): - if channel != "#bots" and not DEBUG: - util.sendmsg( - ircsock, - channel, - "{} is a meanie and gets no tildes. **Tildebot now only gives out tildes in the #bots channel.**".format( - name - ), - ) - return - global challenges - challenge = puzzle.make_puzzle() - challenges[user] = challenge[1:] - util.sendmsg(ircsock, channel, "{}: {}".format(name, challenge[0])) - - -def challenge_response(channel, user, name, time, msg): - global challenges - print(msg) - if user in challenges: - answer, bonus = challenges[user] - if (callable(answer) and answer(msg.lower())) or ( - msg.lower() == str(answer).lower() or msg == p.number_to_words(answer) - ): - give_tilde(channel, user, name, time, True, bonus) - else: - give_tilde(channel, user, name, time, False, 0) - del challenges[user] - # delete the user from challenges either way - - -def rollcall(channel): - util.sendmsg( - ircsock, channel, "tildebot reporting! I respond to !tilde !tildescore" - ) - - -def listen(): - while 1: - - ircmsg = ircsock.recv(2048).decode("utf-8") - for msg in ircmsg.split("\n"): - msg = msg.strip("\n\r") - - if msg[:4] == "PING": - util.ping(ircsock, msg) - continue - - formatted = util.format_message(msg) - # print(formatted) - - if "" == formatted: - continue - - iTime, user, _command, channel, messageText = formatted.split("\t") - name = util.get_name(user) - - if msg.find(":!tildescore") != -1: - show_tildescore(channel, user, name) - elif msg.find(":!tilde") != -1 and user not in challenges: - challenge(channel, user, name, iTime) - elif user in challenges and (channel == "#bots" or DEBUG): - challenge_response(channel, user, name, iTime, messageText) - - if msg.find(":!jackpot") != -1: - show_jackpot(channel) - - if msg.find(":!rollcall") != -1: - rollcall(channel) - - sys.stdout.flush() - time.sleep(1) - - -ircsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) -util.connect(ircsock, args) -listen() diff --git a/Code/irc/topicbot.py b/Code/irc/topicbot.py deleted file mode 100755 index 8fde669..0000000 --- a/Code/irc/topicbot.py +++ /dev/null @@ -1,215 +0,0 @@ -#!/usr/bin/python3 -# http://wiki.shellium.org/w/Writing_an_IRC_bot_in_Python - -# Import some necessary libraries. -import socket -import os -import sys -import fileinput -import random -import time -import argparse - -import inflect -import util - -parser = argparse.ArgumentParser() - -parser.add_argument( - "-s", - "--server", - dest="server", - default="127.0.0.1:6667", - help="the server to connect to", - metavar="SERVER", -) -parser.add_argument( - "-c", - "--channels", - dest="channels", - nargs="+", - default=["#bot_test"], - help="the channels to join", - metavar="CHANNELS", -) -parser.add_argument( - "-n", - "--nick", - dest="nick", - default="topicbot", - help="the nick to use", - metavar="NICK", -) - -args = parser.parse_args() - -p = inflect.engine() - - -def get_topic(channel, user, time): - # topic scores are saved as &^%&^% - with open("topicscores.txt", "r") as scorefile: - scores = scorefile.readlines() - userscore = 1 - found = False - with open("topicscores.txt", "w") as scorefile: - for idx, score in enumerate(scores): - data = score.strip("\n").split("&^%") - if data[0] == user: - found = True - userscore = int(data[1]) + 1 - scores[idx] = data[0] + "&^%" + str(userscore) + "&^%" + data[2] + "\n" - scorefile.writelines(scores) - if not found: - scorefile.write(user + "&^%1&^%0\n") - - with open("topics_" + channel + ".txt", "r") as topics: - topic = topics.readlines()[-1].strip("\n").split("&^%", 3) - byuser = util.get_name(topic[1]) - util.sendmsg( - ircsock, - channel, - "I've told you {} times! It's \"{}\" (set by {} {})".format( - p.number_to_words(userscore), - topic[2], - byuser, - util.pretty_date(int(topic[0])), - ), - ) - - -def count_topic(channel, user, time, msg): - with open("topics_" + channel + ".txt", "a") as topics: - topics.write(time + "&^%" + user + "&^%" + msg + "\n") - with open("topicscores.txt", "r") as scorefile: - scores = scorefile.readlines() - userscore = 1 - found = False - with open("topicscores.txt", "w") as scorefile: - for idx, score in enumerate(scores): - data = score.strip("\n").split("&^%") - if data[0] == user: - found = True - userscore = int(data[2]) + 1 - scores[idx] = data[0] + "&^%" + data[1] + "&^%" + str(userscore) + "\n" - scorefile.writelines(scores) - if not found: - scorefile.write(user + "&^%0&^%1") - util.sendmsg( - ircsock, - channel, - "{} has changed the topic {} times!".format(user, p.number_to_words(userscore)), - ) - - -def set_topic(channel, user, time, msg): - ircsock.send("TOPIC " + channel + " :" + msg + "\n") - count_topic(channel, user, time, msg) - - -def random_topic(channel, user, time, setTopic=False): - with open("randomtopics.txt") as rtopics: - msg = random.choice(rtopics.readlines()).strip("\n") - if setTopic: - set_topic(channel, user, time, msg) - else: - util.sendmsg(ircsock, channel, "Suggested Topic: {}".format(msg)) - - -def rollcall(channel): - util.sendmsg( - ircsock, - channel, - "topicbot reporting! I respond to !topic !settopic !suggesttopic !thistory", - ) - - -def topic_score(channel): - util.sendmsg(ircsock, channel, "Not implemented yet") - - -def topic_scores(channel): - util.sendmsg(ircsock, channel, "Not implemented yet") - - -def topic_history(channel, user, count): - try: - iCount = int(count.split()[1]) - except (ValueError, IndexError): - iCount = 3 - if iCount > 10: - iCount = 10 - if iCount < 1: - iCount = 3 - with open("topics_" + channel + ".txt", "r") as topicsfile: - # topics = topicsfile.readlines()[-iCount:].reverse() - util.sendmsg( - ircsock, - channel, - "Ok, here are the last {} topics".format(p.number_to_words(iCount)), - ) - for idx, topic in enumerate(reversed(topicsfile.readlines()[-iCount:])): - topic = topic.strip("\n").split("&^%", 3) - byuser = util.get_name(topic[1]) - util.sendmsg( - ircsock, - channel, - "{}: {} (set by {} {})".format( - str(idx + 1), topic[2], byuser, util.pretty_date(int(topic[0])) - ), - ) - - -def listen(): - while 1: - - ircmsg = ircsock.recv(2048).decode("utf-8") - for msg in ircmsg.split("\n"): - msg = msg.strip("\n\r") - - if msg[:4] == "PING": - util.ping(ircsock, msg) - continue - - formatted = util.format_message(msg) - - if "" == formatted: - time.sleep(1) - continue - - # print formatted - - msgtime, user, command, channel, messageText = formatted.split("\t") - - if command == "TOPIC" and user != args.nick: - count_topic(channel, user, msgtime, messageText) - - if msg.find(":!topic") != -1: - get_topic(channel, user, msgtime) - - if msg.find(":!settopic") != -1: - set_topic(channel, user, msgtime, messageText[10:]) - - if msg.find(":!tscores") != -1: - topic_scores(channel) - elif msg.find(":!tscores") != -1: - topic_score(channel) - - if msg.find(":!randomtopic") != -1: - random_topic(channel, user, msgtime, True) - if msg.find(":!suggesttopic") != -1: - random_topic(channel, user, msgtime, False) - - if msg.find(":!thistory") != -1: - topic_history(channel, user, messageText) - - if msg.find(":!rollcall") != -1: - rollcall(channel) - - sys.stdout.flush() - time.sleep(1) - - -ircsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) -util.connect(ircsock, args) -listen() diff --git a/Code/irc/tumblr.py b/Code/irc/tumblr.py deleted file mode 100644 index 286848a..0000000 --- a/Code/irc/tumblr.py +++ /dev/null @@ -1,50 +0,0 @@ -#!/usr/bin/python3 -import urllib -from bs4 import BeautifulSoup -import random -import re - - -def tumble(url): - # Find the max pages - soup = BeautifulSoup(urllib.request.urlopen(url).read(), "html.parser") - pages = soup.findAll("span", "page-numbers")[0].text.split("/")[ - 1 - ] # this could totally fail several ways - tries = 3 - while True: - try: - page = random.randrange(1, int(pages) + 1) - - # Parse a page - soup = BeautifulSoup( - urllib.request.urlopen(url + "/page/" + str(page)).read(), "html.parser" - ) - article = random.choice(soup.findAll("article")) - quote = article.find("blockquote").text.replace("\n", "") - if len(article.find("footer").findAll("ul")) > 1: - quote += re.sub( - "\n+", " ", article.find("footer").findAll("ul")[0].text - ) - # the hash tags - quote += ( - "(" - + re.sub("\n+", " ", article.find("footer").findAll("ul")[1].text) - + ")" - ) - # and the date and notes - else: - quote += ( - "(" - + re.sub("\n+", " ", article.find("footer").findAll("ul")[0].text) - + ")" - ) - # just the date and notes - - return quote - except: # sometimes we fail. let's retry a few times - if tries == 0: - return "" - else: - tries -= 1 - break diff --git a/Code/irc/util.py b/Code/irc/util.py deleted file mode 100644 index bd0ca6b..0000000 --- a/Code/irc/util.py +++ /dev/null @@ -1,282 +0,0 @@ -import json -import time -import random -import re - -MAX_LINE = 400 - - -def ping(ircsock, msg): - # print("{} => PONG {}".format(msg, msg.split(" ")[1])) - ircsock.send("PONG {}\n".format(msg.split(" ")[1]).encode()) - - -def sendmsg(ircsock, chan, msg): - print("sending {} to {}".format(msg, chan)[0:MAX_LINE]) - ircsock.send("PRIVMSG {} :{}\r\n".format(chan, msg).encode()[0:MAX_LINE]) - -def notice(ircsock, user, chan, msg): - print("sending notice {} to {} in {}".format(msg, user, chan)[0:MAX_LINE]) - ircsock.send("CNOTICE {} {} :{}\r\n".format(user, chan, msg).encode()[0:MAX_LINE]) - -def part(ircsock, chan, msg="Bye!"): - print("leaving channel {}".format(chan)) - ircsock.send("PART {} {}\r\n".format(chan, msg).encode()) - -def quit(ircsock, msg="Quitting!"): - print("!! quitting !!") - ircsock.send("QUIT {}".format(msg).encode()) - -def joinchan(ircsock, chan): - print("joining {}".format(chan)) - ircsock.send("JOIN {}\r\n".format(chan).encode()) - - -def get_user_from_message(msg): - try: - i1 = msg.index(":") + 1 - i2 = msg.index("!") - return msg[i1:i2] - except ValueError: - return "" - - -def connect(ircsock, options): - print(options) - server, port = options.server.split(":") - ircsock.connect((server, int(port))) - print(ircsock) - nick = "NICK {}\r\n".format(options.nick).encode() - print(nick) - ircsock.send(nick) - login = "USER {0} {0} {0} {0}".format(options.nick).encode() - print(login) - ircsock.send(login) - mode = "MODE +B {}\r\n".format(options.nick).encode() - print(mode) - ircsock.send(mode) - if 'channels' in options: - for channel in options.channels: - joinchan(ircsock, channel) - else: - joinchan(ircsock, options.channel) - - -# integer number to english word conversion -# can be used for numbers as large as 999 vigintillion -# (vigintillion --> 10 to the power 60) -# tested with Python24 vegaseat 07dec2006 -def int2word(n): - """ - convert an integer number n into a string of english words - """ - # break the number into groups of 3 digits using slicing - # each group representing hundred, thousand, million, billion, ... - n3 = [] - r1 = "" - # create numeric string - ns = str(n) - for k in range(3, 33, 3): - r = ns[-k:] - q = len(ns) - k - # break if end of ns has been reached - if q < -2: - break - else: - if q >= 0: - n3.append(int(r[:3])) - elif q >= -1: - n3.append(int(r[:2])) - elif q >= -2: - n3.append(int(r[:1])) - r1 = r - - # print n3 # test - - # break each group of 3 digits into - # ones, tens/twenties, hundreds - # and form a string - nw = "" - for i, x in enumerate(n3): - b1 = x % 10 - b2 = (x % 100) // 10 - b3 = (x % 1000) // 100 - # print b1, b2, b3 # test - if x == 0: - continue # skip - else: - t = thousands[i] - if b2 == 0: - nw = ones[b1] + t + nw - elif b2 == 1: - nw = tens[b1] + t + nw - elif b2 > 1: - nw = twenties[b2] + ones[b1] + t + nw - if b3 > 0: - nw = ones[b3] + "hundred " + nw - return nw - - -############# globals ################ -ones = [ - "", - "one ", - "two ", - "three ", - "four ", - "five ", - "six ", - "seven ", - "eight ", - "nine ", -] -tens = [ - "ten ", - "eleven ", - "twelve ", - "thirteen ", - "fourteen ", - "fifteen ", - "sixteen ", - "seventeen ", - "eighteen ", - "nineteen ", -] -twenties = [ - "", - "", - "twenty ", - "thirty ", - "forty ", - "fifty ", - "sixty ", - "seventy ", - "eighty ", - "ninety ", -] -thousands = [ - "", - "thousand ", - "million ", - "billion ", - "trillion ", - "quadrillion ", - "quintillion ", - "sextillion ", - "septillion ", - "octillion ", - "nonillion ", - "decillion ", - "undecillion ", - "duodecillion ", - "tredecillion ", - "quattuordecillion ", - "sexdecillion ", - "septendecillion ", - "octodecillion ", - "novemdecillion ", - "vigintillion ", -] - - -def format_message(message): - pattern = r"^:.*\!~(.*)@.* (.*) (.*) :(.*)" - now = int(time.time()) - matches = re.match(pattern, message) - if not matches: - return "" - - nick = matches.group(1).strip() - command = matches.group(2).strip() - channel = matches.group(3).strip() - message = matches.group(4).strip() - - return "%s\t%s\t%s\t%s\t%s" % (now, nick, command, channel, message) - - -def get_users(): - # thanks, ~dan! - users = [] - with open("/etc/passwd", "r") as f: - for line in f: - if "/bin/bash" in line: - u = line.split(":")[0] # Grab all text before first ':' - users.append(u) - - return users - - -def get_name(name): - names_file = "/home/jumblesale/Code/canonical_names/canonical_names.json" - try: - with open(names_file) as names_data: - names = json.load(names_data) - try: - return names[name]["userName"] - except KeyError: - return name - except IOError: - return name # if we didn't already - - -def pretty_date(time=False): - """ - Get a datetime object or a int() Epoch timestamp and return a - pretty string like 'an hour ago', 'Yesterday', '3 months ago', - 'just now', etc - """ - from datetime import datetime - - now = datetime.now() - if type(time) is int: - diff = now - datetime.fromtimestamp(time) - elif isinstance(time, datetime): - diff = now - time - elif not time: - diff = now - now - second_diff = diff.seconds - day_diff = diff.days - - if day_diff < 0: - return "" - - if day_diff == 0: - if second_diff < 10: - return "just now" - if second_diff < 60: - return str(second_diff) + " seconds ago" - if second_diff < 120: - return "a minute ago" - if second_diff < 3600: - return str(second_diff / 60) + " minutes ago" - if second_diff < 7200: - return "an hour ago" - if second_diff < 86400: - return str(second_diff / 3600) + " hours ago" - if day_diff == 1: - return "Yesterday" - if day_diff < 7: - return str(day_diff) + " days ago" - if day_diff < 31: - return str(day_diff / 7) + " weeks ago" - if day_diff < 365: - return str(day_diff / 30) + " months ago" - return str(day_diff / 365) + " years ago" - - -def makeRainbow(word): - - word = word or "RAINBOW" - output = "" - rb = ["5", "7", "8", "3", "12", "13", "6"] - bg = "01" - idx = random.randrange(0, len(rb)) - - for l in word: - if l == " ": - output += " " - else: - output += "\x03" + rb[idx % len(rb)] + "," + bg + l - idx += 1 - - return output diff --git a/Code/irc/wangbot.py b/Code/irc/wangbot.py deleted file mode 100755 index faa216b..0000000 --- a/Code/irc/wangbot.py +++ /dev/null @@ -1,322 +0,0 @@ -#!/usr/bin/python -# http://wiki.shellium.org/w/Writing_an_IRC_bot_in_Python - -# Import some necessary libraries. -import socket -import os -import sys -from optparse import OptionParser -import fileinput -import random -import time -import re -import operator - -import inflect -import util - -parser = OptionParser() - -parser.add_option( - "-s", - "--server", - dest="server", - default="127.0.0.1:6667", - help="the server to connect to", - metavar="SERVER", -) -parser.add_option( - "-c", - "--channel", - dest="channel", - default="#bot_test", - help="the channel to join", - metavar="CHANNEL", -) -parser.add_option( - "-n", - "--nick", - dest="nick", - default="wangbot", - help="the nick to use", - metavar="NICK", -) - -(options, args) = parser.parse_args() - -p = inflect.engine() -LIMIT_GUESSING = True -MIN_ROUNDS = 5 -MAX_ROUNDS = 12 -SCORE_FILE = "numberwangscores.txt" -SHOW_TOP_NUM = 5 -GOOD_CHAN = "#bots" - -roundsLeft = 0 -bonusRound = 0 -guesses = 0 -lastGuesser = "" -currentScores = {} - - -def resetGlobals(): - global roundsLeft - global bonusRound - global guesses - global lastGuesser - global currentScores - roundsLeft = 0 - bonusRound = 0 - guesses = 0 - lastGuesser = "" - currentScores.clear() - - -def start_numberwang(channel, user): - if channel != "#bots": - util.sendmsg( - ircsock, - channel, - "Numberwang has been disabled in {} due to spamminess. Please join {} to start a game.".format( - channel, GOOD_CHAN - ), - ) - return - - print(user + " started a game") - resetGlobals() - util.sendmsg(ircsock, channel, "It's time for Numberwang!") - time.sleep(1) - util.sendmsg(ircsock, channel, "Here's how to play:") - - util.sendmsg(ircsock, channel, "1. There are 10 rounds") - util.sendmsg( - ircsock, channel, "2. Each round lasts 10 seconds. You're up against the clock!" - ) - util.sendmsg( - ircsock, channel, "3. Play your numbers, as long as they're between 0 and 99." - ) - util.sendmsg(ircsock, channel, "4. That's Numberwang!") - time.sleep(2) - util.sendmsg(ircsock, channel, "Let's get started!") - global roundsLeft - global bonusRound - roundsLeft = random.randint(MIN_ROUNDS, MAX_ROUNDS) - bonusRound = random.randint(2, roundsLeft - 1) - print( - "There will be {} rounds with the bonus on round {}".format( - str(roundsLeft), str(roundsLeft - bonusRound + 1) - ) - ) - - -def print_scores(channel): - scoreStrs = [] - first = True - for name in currentScores: - scoreStrs.append( - "{} is {} on {}".format( - name, - ("also " if not first and random.randint(1, 3) == 3 else ""), - currentScores[name], - ) - ) - first = False - util.sendmsg(ircsock, channel, p.join(scoreStrs)) - - -def guess_numberwang(channel, user, messageText): - global guesses - global lastGuesser - global currentScores - global roundsLeft - print(user + " guessed '" + messageText + "'") - guess = re.sub( - "[^0-9]", "", messageText.split()[0] - ) # must have a number in the first 'word' - if guess: - if LIMIT_GUESSING and user == lastGuesser: - util.sendmsg( - ircsock, - channel, - "{}, you just guessed! Give another player a try!".format(user), - ) - else: - guesses += 1 - lastGuesser = user - ###CORRECT GUESS### - if ( - random.randint(0, 10) > 10 - guesses - ): # the more guesses, the higher the probability - guesses = 0 - lastGuesser = "" - util.sendmsg(ircsock, channel, "{}: THAT'S NUMBERWANG!".format(user)) - points = random.randint(2, 10) * ( - random.randint(2, 4) if roundsLeft == bonusRound else 1 - ) - if user in currentScores.keys(): - currentScores[user] += points - else: - currentScores[user] = points - roundsLeft -= 1 - time.sleep(2) - if roundsLeft == 0: - util.sendmsg( - ircsock, - channel, - "Numberwang is now over. Thank you for playing!", - ) - util.sendmsg(ircsock, channel, "Final scores:") - print_scores(channel) - save_scores() - else: - print_scores(channel) - newRoundStr = "" - if roundsLeft == 1: - newRoundStr += "The last round is Wangernumb!" - elif roundsLeft == bonusRound: - newRoundStr += "**Bonus Round!**" - else: - newRoundStr += "New Round!" - if random.randint(1, 10) > 8: - newRoundStr += " Let's rotate the board!" - util.sendmsg( - ircsock, channel, "{} Start guessing!".format(newRoundStr) - ) - - ###INCORRECT GUESS### - else: - util.sendmsg( - ircsock, - channel, - "{}, {}, {} Numberwang!".format( - random.choice(["Sorry", "I'm sorry", "No", "Nope"]), - user, - random.choice( - [ - "that's not", - "that is not", - "that isn't", - "that is not", - "that won't make", - "that will not make", - ] - ), - ), - ) - - -def stop_numberwang(channel, user): - print(user + " stopped a game") - resetGlobals() - util.sendmsg( - ircsock, - channel, - "Numberwang has been stopped. No points have been awarded. {} is such a party pooper!".format( - user - ), - ) - - -def save_scores(): - with open(SCORE_FILE, "r+") as scorefile: - scores = scorefile.readlines() - scorefile.seek(0) - scorefile.truncate() - for line in scores: - for name in currentScores: - score = line.strip("\n").split("&^%") - if score[0] == name: - line = "{}&^%{}\n".format( - score[0], int(score[1]) + currentScores[name] - ) - del currentScores[name] - break - scorefile.write(line) - - for name in currentScores: # new wangers - scorefile.write("{}&^%{}\n".format(name, currentScores[name])) - - -def show_highscores(channel): - with open(SCORE_FILE, "r") as scorefile: - scores = [] - for line in scorefile.readlines(): - sline = line.strip("\n").split("&^%") - scores.append((int(sline[1]), sline[0])) - scores = sorted(scores, reverse=True)[:SHOW_TOP_NUM] - - util.sendmsg(ircsock, channel, "====TOP WANGERS====") - for score in scores: - util.sendmsg( - ircsock, channel, " :== ~{} ({} points!) ==".format(score[1], score[0]) - ) - - -def show_user_score(channel, user): - with open(SCORE_FILE, "r") as scorefile: - for line in scorefile.readlines(): - score = line.strip("\n").split("&^%") - if user == score[0]: - util.sendmsg( - ircsock, - channel, - "{}: Your global numberwang score is {}!".format(user, score[1]), - ) - return - # if we don't find a score line - util.sendmsg( - ircsock, channel, "{} You haven't scored any points yet!".format(user) - ) - - -def rollcall(channel): - util.sendmsg( - ircsock, - channel, - "Is it time for Numberwang? It might be! Start a new game with !numberwang or stop a current game with !wangernumb Get your score with !myscore and the list of top wangers with !topwangers", - ) - - -def listen(): - while 1: - - ircmsg = ircsock.recv(2048).decode("utf-8") - ircmsg = ircmsg.strip("\n\r") - - if ircmsg[:4] == "PING": - util.ping(ircsock, ircmsg) - - formatted = util.format_message(ircmsg) - - if "" == formatted: - continue - - # print formatted - - _time, user, _command, channel, messageText = formatted.split("\t") - - if ircmsg.find(":!numberwang") != -1 and roundsLeft == 0: - start_numberwang(channel, user) - - if channel == GOOD_CHAN: - if ircmsg.find(":!wangernumb") != -1 and roundsLeft > 0: - stop_numberwang(channel, user) - if roundsLeft > 0: - guess_numberwang(channel, user, messageText) - - if ircmsg.find(":!topwangers") != -1: - show_highscores(channel) - if ircmsg.find(":!myscore") != -1: - show_user_score(channel, user) - - if ircmsg.find(":!rollcall") != -1: - rollcall(channel) - - sys.stdout.flush() - time.sleep(1) - - -ircsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) -util.connect(ircsock, options) -listen() diff --git a/Code/irc/welch.py b/Code/irc/welch.py deleted file mode 100644 index 563d96b..0000000 --- a/Code/irc/welch.py +++ /dev/null @@ -1,10 +0,0 @@ -import random - - -def get_thing(): - file = "/home/krowbar/logs/welchdata.txt" - thing = "" - return ( - "Thing Mr. Welch can no longer do in a RPG #" - + random.choice(list(open(file))).rstrip() - ) diff --git a/Code/irc/whosaid.py b/Code/irc/whosaid.py deleted file mode 100755 index 95fa54f..0000000 --- a/Code/irc/whosaid.py +++ /dev/null @@ -1,47 +0,0 @@ -#!/usr/bin/python3 -import fileinput -import time -import calendar -import re -import operator - -MAX_NODES = 5 - -logfile = "/home/archangelic/irc/log" -timeCutoff = calendar.timegm(time.gmtime()) - (3 * 7 * 24 * 60 * 60) # 3 weeks - -nameFix = { - "jumblesal": "jumblesale", - "hardmath1": "kc", - "hardmath123": "kc", - "bendorphan": "endorphant", - "endorphan": "endorphant", - "synergian": "synergiance", -} - - -def whoSaid(word): - word = word.lower() - userData = ( - {} - ) # hash keyed by "user" that contains a hash of mentioned other users with count - # Get a list of all user names by checking the logs for people who have said things - with open(logfile, "r") as log: - for line in log: - try: - time, user, message = line.split("\t", 3) - time = int(time) - if user in nameFix: - user = nameFix[user] - else: - user = user.lower() - except ValueError: - continue # There are some bad lines in the log file that we'll ignore if we can't parse - - if time > timeCutoff and message[0] is not "!" and word in message.lower(): - if user in userData: - userData[user] += 1 - else: - userData[user] = 1 - userData = sorted(userData.items(), key=operator.itemgetter(1), reverse=True) - return {"timecutoff": timeCutoff, "data": userData} diff --git a/Code/irc/wikiphilosophy.py b/Code/irc/wikiphilosophy.py deleted file mode 100644 index be1eab1..0000000 --- a/Code/irc/wikiphilosophy.py +++ /dev/null @@ -1,87 +0,0 @@ -#!/usr/bin/python3 -from bs4 import BeautifulSoup -import random -import requests - - -def get_philosophy(word, max_steps=20): - step_words = [word] - steps = 0 - - url = "https://en.wikipedia.org/wiki/%s" % word - while steps < max_steps: - print("url: {}".format(url)) - soup = BeautifulSoup(requests.get(url).content, "html.parser") - title = soup.find("h1", id="firstHeading") - content = soup.find("div", id="mw-content-text") - if not content: - break - item = [ - item - for item in content.find_all("a") - if not item.get("class") - and not item.get("target") - and item.get("title") - and not "Wikipedia:" in item.get("title") - and not "Category:" in item.get("title") - and not "Help:" in item.get("title") - and not "Portal:" in item.get("title") - and not "Special:" in item.get("title") - and not "Talk:" in item.get("title") - and not "Template:" in item.get("title") - and not "File:" in item.get("title") - and "Edit section:" not in item.get("title") - and "Commons:" not in item.get("title") - and not item.get("title") in step_words - ][0] - step_words.append(item.get("title")) - # print item.get('title') + "\n" - url = "https://en.wikipedia.org{}".format(item.get("href")) - steps += 1 - return step_words - - -def containsAny(str, set): - return 1 in [c in str for c in set] - - -def get_philosophy_lower(word, max_steps=20): - step_words = [word] - steps = 0 - - url = "https://en.wikipedia.org/wiki/{}".format(word.replace(" ", "%20")) - while steps < max_steps: - print("url: {}".format(url)) - soup = BeautifulSoup(requests.get(url).content, "html.parser") - - if soup.find(id="noarticletext"): - step_words.append("(not found)") - break - - title = soup.find("h1", id="firstHeading") - content = soup.find("div", id="mw-content-text") - if not content: - break - links = [ - item - for item in content.find_all("a") - if not item.get("class") - and item.text - and item.text[0].islower() - and not containsAny(item.text, ":()") - and item.get("title") - and not containsAny(item.get("title"), ":()") - and not item.get("title") in step_words - ] - if not links: - step_words.append("(dead end)") - break - item = links[0] # grab the first good link item - # print "Checking %s %s" % (item.get('title'), item.text) - step_words.append(item.get("title")) - if item.get("title") == "Philosophy": - break - # print item.get('title') + "\n" - url = "https://en.wikipedia.org%s" % item.get("href") - steps += 1 - return step_words diff --git a/Code/irc/xkcdApropos.py b/Code/irc/xkcdApropos.py deleted file mode 100644 index fd73042..0000000 --- a/Code/irc/xkcdApropos.py +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/python3 -import duckduckgo -import urllib -from bs4 import BeautifulSoup - - -def xkcd(query): - res = duckduckgo.get_zci("site:xkcd.com " + query) - title = "" - try: # ddg returns a url for these searches. i want a title as well - title = BeautifulSoup(urllib.urlopen(res).read(), "html.parser").title.text - except: - pass # just swallow the error. maybe the result wasn't a url or something else bad happened - return [(((title + " - ") if title else "") + res)] - - -# never mind, blocked by ddg -# def xkcd_links(query): -# url = "https://duckduckgo.com/html/?q=site%3Axkcd.com+" + query.replace(' ', '+') -# soup = BeautifulSoup(urllib.urlopen(url).read(), 'html.parser') -# items = soup.find_all("a", class_="result__a") -# print items -# items = list(filter(lambda i: i[0:8] == 'xkcd.com', -# [i.find(class_="result__title").text.strip() for i in items])) -# print items -# def pretty_link(item): -# url = item.find(class_="result__url").text.strip() -# title = item.find(class_="result__title").text.strip() -# return (title + ' - ' + url) if title else url -# -# links = map(lambda url: pretty_link(url), items) -# return links