3
\$\begingroup\$

The following function removes text inside parenthesis, also checks for balanced brackets. Example: RemoveTextInsideParenthesis('Yahoo (Inc)') will return 'Yahoo' Any suggestions in how to improve readability/simplify it?

def RemoveTextInsideParenthesis(text: str) -> str:
  """Remove text inside brackets or nested brackets.

  Creates an array: ['(',')'...], then for each character in text string
  we compare if character is a bracket, if it is we update a status array.
  Based on status array we can evaluate if brackets are open and close correctly
  and then capture text outside parenthesis.
  Using divmod function we extract index of brackets array.
  Take two (non complex) numbers as arguments and return a pair of numbers
  consisting of their quotient and remainder.
  Documentation for brackets:
  https://www.unicode.org/charts/nameslist/n_2000.html

  Args:
    text: Text to be clean up.

  Returns:
    Text inside parenthesis
  """

  openers = (u'(<[{\u0f3a\u0f3c\u169b\u2045\u207d\u208d\u2329\u2768'
             u'\u276a\u276c\u276e\u2770\u2772\u2774\u27c5\u27e6\u27e8\u27ea'
             u'\u27ec\u27ee\u2983\u2985\u2987\u2989\u298b\u298d\u298f\u2991'
             u'\u2993\u2995\u2997\u29d8\u29da\u29fc\u2e22\u2e24\u2e26\u2e28'
             u'\u3008\u300a\u300c\u300e\u3010\u3014\u3016\u3018\u301a\u301d'
             u'\u301d\ufd3e\ufe17\ufe35\ufe37\ufe39\ufe3b\ufe3d\ufe3f\ufe41'
             u'\ufe43\ufe47\ufe59\ufe5b\ufe5d\uff08\uff3b\uff5b\uff5f\uff62'
             u'\xab\u2018\u201c\u2039\u2e02\u2e04\u2e09\u2e0c\u2e1c\u2e20'
             u'\u201a\u201e\xbb\u2019\u201d\u203a\u2e03\u2e05\u2e0a\u2e0d'
             u'\u2e1d\u2e21\u201b\u201f')
  closers = (u')>]}\u0f3b\u0f3d\u169c\u2046\u207e\u208e\u232a\u2769'
             u'\u276b\u276d\u276f\u2771\u2773\u2775\u27c6\u27e7\u27e9\u27eb'
             u'\u27ed\u27ef\u2984\u2986\u2988\u298a\u298c\u298e\u2990\u2992'
             u'\u2994\u2996\u2998\u29d9\u29db\u29fd\u2e23\u2e25\u2e27\u2e29'
             u'\u3009\u300b\u300d\u300f\u3011\u3015\u3017\u3019\u301b\u301e'
             u'\u301f\ufd3f\ufe18\ufe36\ufe38\ufe3a\ufe3c\ufe3e\ufe40\ufe42'
             u'\ufe44\ufe48\ufe5a\ufe5c\ufe5e\uff09\uff3d\uff5d\uff60\uff63'
             u'\xbb\u2019\u201d\u203a\u2e03\u2e05\u2e0a\u2e0d\u2e1d\u2e21'
             u'\u201b\u201f\xab\u2018\u201c\u2039\u2e02\u2e04\u2e09\u2e0c'
             u'\u2e1c\u2e20\u201a\u201e')

  # Interleave openers and closers: ['(',')'...]
  brackets = [value for pair in zip(openers, closers) for value in pair]
  count = [0] * (len(brackets) // 2)  # Count open/close brackets as array.
  clean_string = []
  for character in text:
    for i, bracket in enumerate(brackets):
      if character == bracket:  # Found a bracket in text.
        # Take index(i) of brackets and 2 as arguments, return a tuple
        # consisting of their quotient and remainder (a, b).
        # When index is even, reminder = 0 is an open bracket.
        # ['(',')','[',']',...] = [0, 1, 2, 3,...]
        bracket_kind, is_close = divmod(i, 2)
        # Keep track of brackets in string via count array by adding 1 when an
        # open bracket is seen or substracting 1 when is closed.
        # (-1)**0 = 1, (-1)**1 = -1. Balanced brackets, sum will be 0.
        count[bracket_kind] += (-1)**is_close
        if count[bracket_kind] < 0:  # Unbalanced bracket.
          count[bracket_kind] = 0
        break
    else:  # Character is not a bracket.
      if not any(count):  # Outside brackets.
        clean_string.append(character)
  # Return text outside brackets or text if after removing brackets is empty.
  return ''.join(clean_string).strip() if clean_string else text.strip()
\$\endgroup\$
  • 1
    \$\begingroup\$ Could you give a few more examples of what the function needs to do? I'm not really understanding the idea behind... \$\endgroup\$ – RandomDude Jul 25 '18 at 7:06
  • 1
    \$\begingroup\$ Also can you give more details about the constraints you are trying to implement? You say that the code check for balanced brackets but 'This is [a test { and a simple] one}. Isn\'t it?' is shortened to 'This is . Isn\'t it?'; this doesn't feel like any balancing is at play, only that the first opener is matched to the last closer… I would have expected something like 'This is one}. Isn\'t it?' instead or at least 'This is [a test . Isn\'t it?'. \$\endgroup\$ – 301_Moved_Permanently Jul 25 '18 at 7:57
  • \$\begingroup\$ I'm looking for a way to improve readability, I needed to add many comments for my colleagues to understand the algorithm, probably a simpler way to do it? \$\endgroup\$ – gogasca Jul 25 '18 at 17:21