nodes: 0, module; 1, function_definition; 2, function_name:regex_opt_inner; 3, parameters; 4, block; 5, identifier:strings; 6, identifier:open_paren; 7, expression_statement; 8, expression_statement; 9, comment:# print strings, repr(open_paren); 10, if_statement; 11, expression_statement; 12, if_statement; 13, if_statement; 14, if_statement; 15, expression_statement; 16, if_statement; 17, comment:# is there a suffix?; 18, expression_statement; 19, expression_statement; 20, if_statement; 21, comment:# recurse on common 1-string prefixes; 22, comment:# print '-> last resort'; 23, return_statement; 24, comment:"""Return a regex that matches any string in the sorted list of strings."""; 25, assignment; 26, not_operator; 27, comment:# print '-> nothing left'; 28, block; 29, assignment; 30, comparison_operator:len(strings) == 1; 31, comment:# print '-> only 1 string'; 32, block; 33, not_operator; 34, comment:# print '-> first string empty'; 35, block; 36, comparison_operator:len(first) == 1; 37, comment:# multiple one-char strings? make a charset; 38, block; 39, assignment; 40, identifier:prefix; 41, block; 42, assignment; 43, assignment; 44, identifier:suffix; 45, block; 46, binary_operator:open_paren + \
          '|'.join(regex_opt_inner(list(group[1]), '')
                   for group in groupby(strings, lambda s: s[0] == first[0])) \
          + close_paren; 47, identifier:close_paren; 48, boolean_operator; 49, identifier:strings; 50, return_statement; 51, identifier:first; 52, subscript; 53, call; 54, integer:1; 55, return_statement; 56, identifier:first; 57, return_statement; 58, call; 59, integer:1; 60, expression_statement; 61, expression_statement; 62, for_statement; 63, if_statement; 64, identifier:prefix; 65, call; 66, expression_statement; 67, comment:# we have a prefix for all strings; 68, comment:# print '-> prefix:', prefix; 69, return_statement; 70, identifier:strings_rev; 71, list_comprehension; 72, identifier:suffix; 73, call; 74, expression_statement; 75, comment:# print '-> suffix:', suffix[::-1]; 76, return_statement; 77, binary_operator:open_paren + \
          '|'.join(regex_opt_inner(list(group[1]), '')
                   for group in groupby(strings, lambda s: s[0] == first[0])); 78, line_continuation:\; 79, identifier:close_paren; 80, boolean_operator; 81, string; 82, string; 83, identifier:strings; 84, integer:0; 85, identifier:len; 86, argument_list; 87, binary_operator:open_paren + escape(first) + close_paren; 88, binary_operator:open_paren + regex_opt_inner(strings[1:], '(?:') \
              + '?' + close_paren; 89, identifier:len; 90, argument_list; 91, assignment; 92, assignment; 93, identifier:s; 94, identifier:strings; 95, block; 96, comparison_operator:len(oneletter) > 1; 97, comment:# do we have more than one oneletter string?; 98, block; 99, identifier:commonprefix; 100, argument_list; 101, assignment; 102, binary_operator:open_paren + escape(prefix) \
              + regex_opt_inner([s[plen:] for s in strings], '(?:') \
              + close_paren; 103, subscript; 104, for_in_clause; 105, identifier:commonprefix; 106, argument_list; 107, assignment; 108, binary_operator:open_paren \
              + regex_opt_inner(sorted(s[:-slen] for s in strings), '(?:') \
              + escape(suffix[::-1]) + close_paren; 109, identifier:open_paren; 110, call; 111, identifier:open_paren; 112, string; 113, identifier:strings; 114, binary_operator:open_paren + escape(first); 115, identifier:close_paren; 116, binary_operator:open_paren + regex_opt_inner(strings[1:], '(?:') \
              + '?'; 117, identifier:close_paren; 118, identifier:first; 119, identifier:oneletter; 120, list; 121, identifier:rest; 122, list; 123, if_statement; 124, call; 125, integer:1; 126, if_statement; 127, comment:# print '-> only 1-character'; 128, return_statement; 129, identifier:strings; 130, identifier:plen; 131, call; 132, binary_operator:open_paren + escape(prefix) \
              + regex_opt_inner([s[plen:] for s in strings], '(?:'); 133, line_continuation:\; 134, identifier:close_paren; 135, identifier:s; 136, slice; 137, identifier:s; 138, identifier:strings; 139, identifier:strings_rev; 140, identifier:slen; 141, call; 142, binary_operator:open_paren \
              + regex_opt_inner(sorted(s[:-slen] for s in strings), '(?:') \
              + escape(suffix[::-1]); 143, identifier:close_paren; 144, attribute; 145, generator_expression; 146, string_content:); 147, identifier:open_paren; 148, call; 149, binary_operator:open_paren + regex_opt_inner(strings[1:], '(?:'); 150, line_continuation:\; 151, string; 152, comparison_operator:len(s) == 1; 153, block; 154, else_clause; 155, identifier:len; 156, argument_list; 157, identifier:rest; 158, comment:# print '-> 1-character + rest'; 159, block; 160, binary_operator:open_paren + make_charset(oneletter) + close_paren; 161, identifier:len; 162, argument_list; 163, binary_operator:open_paren + escape(prefix); 164, line_continuation:\; 165, call; 166, unary_operator; 167, identifier:len; 168, argument_list; 169, binary_operator:open_paren \
              + regex_opt_inner(sorted(s[:-slen] for s in strings), '(?:'); 170, line_continuation:\; 171, call; 172, string; 173, identifier:join; 174, call; 175, for_in_clause; 176, identifier:escape; 177, argument_list; 178, identifier:open_paren; 179, call; 180, string_content:?; 181, call; 182, integer:1; 183, expression_statement; 184, block; 185, identifier:oneletter; 186, return_statement; 187, binary_operator:open_paren + make_charset(oneletter); 188, identifier:close_paren; 189, identifier:prefix; 190, identifier:open_paren; 191, call; 192, identifier:regex_opt_inner; 193, argument_list; 194, integer:1; 195, identifier:suffix; 196, identifier:open_paren; 197, line_continuation:\; 198, call; 199, identifier:escape; 200, argument_list; 201, string_content:|; 202, identifier:regex_opt_inner; 203, argument_list; 204, identifier:group; 205, call; 206, identifier:first; 207, identifier:regex_opt_inner; 208, argument_list; 209, identifier:len; 210, argument_list; 211, call; 212, expression_statement; 213, binary_operator:open_paren + regex_opt_inner(rest, '') + '|' \
                      + make_charset(oneletter) + close_paren; 214, identifier:open_paren; 215, call; 216, identifier:escape; 217, argument_list; 218, list_comprehension; 219, string; 220, identifier:regex_opt_inner; 221, argument_list; 222, subscript; 223, call; 224, string; 225, identifier:groupby; 226, argument_list; 227, subscript; 228, string; 229, identifier:s; 230, attribute; 231, argument_list; 232, call; 233, binary_operator:open_paren + regex_opt_inner(rest, '') + '|' \
                      + make_charset(oneletter); 234, identifier:close_paren; 235, identifier:make_charset; 236, argument_list; 237, identifier:prefix; 238, subscript; 239, for_in_clause; 240, string_content:(?:; 241, call; 242, string; 243, identifier:suffix; 244, slice; 245, identifier:list; 246, argument_list; 247, identifier:strings; 248, lambda; 249, identifier:strings; 250, slice; 251, string_content:(?:; 252, identifier:oneletter; 253, identifier:append; 254, identifier:s; 255, attribute; 256, argument_list; 257, binary_operator:open_paren + regex_opt_inner(rest, '') + '|'; 258, line_continuation:\; 259, call; 260, identifier:oneletter; 261, identifier:s; 262, slice; 263, identifier:s; 264, identifier:strings; 265, identifier:sorted; 266, generator_expression; 267, string_content:(?:; 268, unary_operator; 269, subscript; 270, lambda_parameters; 271, comparison_operator:s[0] == first[0]; 272, integer:1; 273, identifier:rest; 274, identifier:append; 275, identifier:s; 276, binary_operator:open_paren + regex_opt_inner(rest, ''); 277, string; 278, identifier:make_charset; 279, argument_list; 280, identifier:plen; 281, subscript; 282, for_in_clause; 283, integer:1; 284, identifier:group; 285, integer:1; 286, identifier:s; 287, subscript; 288, subscript; 289, identifier:open_paren; 290, call; 291, string_content:|; 292, identifier:oneletter; 293, identifier:s; 294, slice; 295, identifier:s; 296, identifier:strings; 297, identifier:s; 298, integer:0; 299, identifier:first; 300, integer:0; 301, identifier:regex_opt_inner; 302, argument_list; 303, unary_operator; 304, identifier:rest; 305, string; 306, identifier:slen
code: def regex_opt_inner(strings, open_paren):
      """Return a regex that matches any string in the sorted list of strings."""
      close_paren = open_paren and ')' or ''
      # print strings, repr(open_paren)
      if not strings:
          # print '-> nothing left'
          return ''
      first = strings[0]
      if len(strings) == 1:
          # print '-> only 1 string'
          return open_paren + escape(first) + close_paren
      if not first:
          # print '-> first string empty'
          return open_paren + regex_opt_inner(strings[1:], '(?:') \
              + '?' + close_paren
      if len(first) == 1:
          # multiple one-char strings? make a charset
          oneletter = []
          rest = []
          for s in strings:
              if len(s) == 1:
                  oneletter.append(s)
              else:
                  rest.append(s)
          if len(oneletter) > 1:  # do we have more than one oneletter string?
              if rest:
                  # print '-> 1-character + rest'
                  return open_paren + regex_opt_inner(rest, '') + '|' \
                      + make_charset(oneletter) + close_paren
              # print '-> only 1-character'
              return open_paren + make_charset(oneletter) + close_paren
      prefix = commonprefix(strings)
      if prefix:
          plen = len(prefix)
          # we have a prefix for all strings
          # print '-> prefix:', prefix
          return open_paren + escape(prefix) \
              + regex_opt_inner([s[plen:] for s in strings], '(?:') \
              + close_paren
      # is there a suffix?
      strings_rev = [s[::-1] for s in strings]
      suffix = commonprefix(strings_rev)
      if suffix:
          slen = len(suffix)
          # print '-> suffix:', suffix[::-1]
          return open_paren \
              + regex_opt_inner(sorted(s[:-slen] for s in strings), '(?:') \
              + escape(suffix[::-1]) + close_paren
      # recurse on common 1-string prefixes
      # print '-> last resort'
      return open_paren + \
          '|'.join(regex_opt_inner(list(group[1]), '')
                   for group in groupby(strings, lambda s: s[0] == first[0])) \
          + close_paren