5
\$\begingroup\$

I've written a python script to replace certain placeholders in a text with defined phrases. Some of the phrases might contain placeholders themselves, so the script needs to recursively replace them. Additionally the placeholders might allow parameters that need to be inserted at certain positions.

The current approach feels a little slow, because I'm iterating over the text much. It also fails (and crashes) if not enough parameters are provided for a parameterizable placeholder.

import re

parameters_regex = "(?:\[(.*)\])?"

def expand_message(message):
  """Recursivly replaces any occurencys of building blocks with its text."""
  for key, value in phrases.items():
    match = re.search(key + parameters_regex, message)
    if match:
      replacement = ""
      if (match.group(1)):
        parameters = match.group(1).split(",")
        replacement = value.format(*parameters)     
      else:
        replacement = value
      replacement = expand_message(replacement)
      message = message.replace(match.group(0), replacement)
  return message


def format_numerators(message):
  """Replaces the numerator placeholders with the actual numerator."""    
  numerator = 1
  while ('#.)' in message):
    message = message.replace('#.)', str(numerator) + ".)", 1)
    numerator+=1
  return message


def format_message(message):
  """Formats and returns the message."""      
  message = expand_message(message)
  message = format_numerators(message)
  return message

This is how I'm testing it at the moment:

phrases = { }
phrases["bb:WORKDAY"] = "bb:GET_UP\nbb:BRUSH_TEETH\nbb:GO_TO_WORK[train]\nbb:GO_HOME"
phrases["bb:FRIDAY"] = "bb:WORKDAY\nbb:GO_OUT[cinema,John]\nbb:GO_HOME"
phrases["bb:WEEKEND"] = "bb:GET_UP\nbb:GO_OUT[park,Mary]\nbb:GO_HOME"

phrases["bb:GET_UP"] = "#.) Get out of bed."
phrases["bb:BRUSH_TEETH"] = "#.) Brush your teeth."
phrases["bb:GO_TO_WORK"] = "#.) Take the {} and go to work."
phrases["bb:GO_HOME"] = "#.) Go home."
phrases["bb:GET_UP"] = "#.) Get out of bed."
phrases["bb:GO_OUT"] = "#.) Go to the {} with {}."
phrases["bb:GET_UP"] = "#.) Get out of bed." 

print(format_message("bb:WORKDAY"))
print("\n")
print(format_message("bb:FRIDAY"))  
print("\n")
print(format_message("bb:WEEKEND"))  

1.) Get out of bed.
2.) Brush your teeth.
3.) Take the train and go to work.
4.) Go home.

1.) Get out of bed.
2.) Brush your teeth.
3.) Take the train and go to work.
4.) Go home.
5.) Go to the cinema with John.
6.) Go home.

1.) Get out of bed.
2.) Go to the park with Mary.
3.) Go home.

\$\endgroup\$
2
  • 1
    \$\begingroup\$ I'm concerned with, "It also fails (and crashes) if not enough parameters are provided for a parameterizable placeholder." is this not intended? If so, your code may be off-topic here as we only allow code that works as you intend, however slow it may be. \$\endgroup\$
    – Peilonrayz
    Aug 14, 2017 at 8:57
  • \$\begingroup\$ The code itself works as intended as I currently assume that the right number of parameters is provided. \$\endgroup\$
    – DIF
    Aug 14, 2017 at 9:00

1 Answer 1

5
\$\begingroup\$

What if you would use re.sub() with a replacement function until there are no unfulfilled placeholders left. Something along these lines:

PHRASE_PATTERN = re.compile(r"(bb:\w+)(?:\[(.*)\])?")

def expand_message(message):
    """Recursively replaces any occurrences of building blocks with its text."""
    while "bb:" in message:
        message = PHRASE_PATTERN.sub(lambda group: phrases[group[1]].format(*group[2].split(","))
                                                   if group[2] else phrases[group[1]],
                                     message)
    return message

This way you don't need to iterate over all the available phrases and only handling the phrases used in a message. Should scale much better.

\$\endgroup\$
1
  • \$\begingroup\$ Thank you! I was not aware of re.sub() - seems to be the perfect tool for my problem \$\endgroup\$
    – DIF
    Aug 16, 2017 at 5:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.