moss-n-puddles/utils/word_list.py
Howard Abrams 2719bce82b Fix numerous bugs
Finally fixed the 'alias' bug that has plaqued me.
2025-08-12 13:55:18 -07:00

150 lines
4.5 KiB
Python
Executable file

#!/usr/bin/env python
from itertools import batched
from random import choice
from re import compile, sub, split, match
from evennia.utils import logger, dedent
def paragraph(text):
"""
Removes initial spaces as well as final newlines.
Blank lines, however, are preserved.
"""
# Shame we can chain this or _thread_, but:
return sub(r";;", "\n\n",
sub(r"\n", " ",
sub(r"\n\n+", ";;",
dedent(text)))).strip()
def fix_msg(text):
if text and isinstance(text, str) and len(text) > 0:
return capitalize_line(text)
elif text and isinstance(text, tuple):
return (capitalize_line(text[0]), text[1])
else:
return text
def capitalize_line(line):
"""
Return a capitalized version of 'line'.
"""
# logger.info(f"Fixing {line}")
if not line or line.strip() == "":
return line
elif match(r"^\|[bm][a-z].*", line):
return "The " + line
elif match(r"^\|[A-z][a-z].*", line):
return line[0:2] + line[2].upper() + line[3:]
else:
return line[0].upper() + line[1:]
def squish(text):
"Remove series of spaces from the text."
no_start = sub(r"\( +", "(", text)
no_after = sub(r" +\)", ")", no_start)
no_inside = sub(r"\" *(.*?) *\"", "\"\\1\"", no_after)
return sub('[ \t]+', ' ', no_inside).strip()
def _routput_choose(text):
"""
Pick a choice when text is: one ^ two ^ three
Done by splitting the text, and calling random.choice().
"""
choices = split(r" *\^ *", text)
return choice(choices)
def _routput_empty(entry):
"""
Return True if entry is empty, e.g. None or blank.
False otherwise. Note: Spaces are ignored.
"""
if entry:
if isinstance(entry, str) and entry.strip() == '':
return True
if isinstance(entry, (list, tuple)) and len(entry) == 0:
return True
return False
return True
def _routput_pair(no_choice, choices = None):
"""
Return a list based on the ^-separated options in 'choices'.
Give a pair of split items, the 'no_choice' is the first section
(before the << ... >>>), and the 'choices' is the section between
the '<< ... >>' delimiter.
"""
# While unlikely, the text before << and the options between the
# << ...>> text may be blank:
if _routput_empty(no_choice) and _routput_empty(choices):
return ''
# If we start a string with <<...>>, then thte 'no_choice' option
# is blank, so we only return a choice:
if _routput_empty(no_choice):
return _routput_choose(choices)
# With text before, but not inside the <<...>> section, we just
# return the first part:
if _routput_empty(choices):
return no_choice
return no_choice + ' ' + _routput_choose(choices)
def routput(text, *substitutions):
"""
Return string with internal word choices replaced randomly.
For instance, the string:
'This feels <<^ very ^ quite>> <<nice^cozy^comfortable>>.'
Could return any of the following strings:
'This feels quite nice.'
'This feels cozy.'
'This feels very comfortable.'
"""
if text:
# section is a list of some phrase followed by another phrase
# that contains ^-separate choices:
sections = split(r" *<< *(.*?) *>> *", text)
# Parts are the first section followed by the _rendered_
# choices, so this^that is either 'this' or 'that':
parts = [_routput_pair(*pair) for pair in batched(sections, 2)]
# The parts may have empty strings, so we filter those out,
# leaving on the phrases to join:
phrases = [phrase for phrase in parts if not _routput_empty(phrase)]
if substitutions:
proposal = ' '.join(phrases).format(*substitutions)
else:
proposal = ' '.join(phrases)
# If a choice is at the end of a sentence, and we could have
# "no choice", as in:
# "He searches <<thoroughly ^ quickly ^>>."
# We don't want a version that looks like:
# "He searches # ."
# with a space before the punctuation:
#
# Also, we should remove all double spaces that may show:
return squish(sub(r"\s+([!?.,])", "\\1", proposal))
def choices(text, *substitutions):
"""
Returns a section of 'text' based on separating semicolons.
Note that text can already be separated as a list or tuple.
"""
if isinstance(text, str):
text = split(r"\s*;;\s*", text)
if text:
return routput(choice(text), *substitutions)