nodes: 0, module; 1, function_definition; 2, function_name:AdvSearch; 3, parameters; 4, block; 5, identifier:document; 6, identifier:search; 7, default_parameter; 8, expression_statement; 9, comment:# Compile the search regexp; 10, expression_statement; 11, expression_statement; 12, comment:# Will match against searchels. Searchels is a list that contains last; 13, comment:# n text elements found in the document. 1 < n < bs; 14, expression_statement; 15, for_statement; 16, return_statement; 17, identifier:bs; 18, integer:3; 19, string; 20, assignment; 21, assignment; 22, assignment; 23, identifier:element; 24, call; 25, block; 26, call; 27, string_content:Return set of all regex matches
  
      This is an advanced version of python-docx.search() that takes into
      account blocks of <bs> elements at a time.
  
      What it does:
      It searches the entire document body for text blocks.
      Since the text to search could be spawned across multiple text blocks,
      we need to adopt some sort of algorithm to handle this situation.
      The smaller matching group of blocks (up to bs) is then adopted.
      If the matching group has more than one block, blocks other than first
      are cleared and all the replacement text is put on first block.
  
      Examples:
      original text blocks : [ 'Hel', 'lo,', ' world!' ]
      search : 'Hello,'
      output blocks : [ 'Hello,' ]
  
      original text blocks : [ 'Hel', 'lo', ' __', 'name', '__!' ]
      search : '(__[a-z]+__)'
      output blocks : [ '__name__' ]
  
      @param instance  document: The original document
      @param str       search: The text to search for (regexp)
                            append, or a list of etree elements
      @param int       bs: See above
  
      @return set      All occurences of search string; 28, identifier:searchre; 29, call; 30, identifier:matches; 31, list; 32, identifier:searchels; 33, list; 34, attribute; 35, argument_list; 36, if_statement; 37, identifier:set; 38, argument_list; 39, attribute; 40, argument_list; 41, identifier:document; 42, identifier:iter; 43, comparison_operator:element.tag == '{%s}t' % nsprefixes['w']; 44, comment:# t (text) elements; 45, block; 46, identifier:matches; 47, identifier:re; 48, identifier:compile; 49, identifier:search; 50, attribute; 51, binary_operator:'{%s}t' % nsprefixes['w']; 52, if_statement; 53, identifier:element; 54, identifier:tag; 55, string; 56, subscript; 57, attribute; 58, comment:# Add this element to searchels; 59, block; 60, string_content:{%s}t; 61, identifier:nsprefixes; 62, string; 63, identifier:element; 64, identifier:text; 65, expression_statement; 66, if_statement; 67, comment:# Search all combinations, of searchels, starting from; 68, comment:# smaller up to bigger ones; 69, comment:# l = search lenght; 70, comment:# s = search start; 71, comment:# e = element IDs to merge; 72, expression_statement; 73, for_statement; 74, string_content:w; 75, call; 76, comparison_operator:len(searchels) > bs; 77, comment:# Is searchels is too long, remove first elements; 78, block; 79, assignment; 80, identifier:l; 81, call; 82, block; 83, attribute; 84, argument_list; 85, call; 86, identifier:bs; 87, expression_statement; 88, identifier:found; 89, False; 90, identifier:range; 91, argument_list; 92, if_statement; 93, for_statement; 94, identifier:searchels; 95, identifier:append; 96, identifier:element; 97, identifier:len; 98, argument_list; 99, call; 100, integer:1; 101, binary_operator:len(searchels)+1; 102, identifier:found; 103, block; 104, identifier:s; 105, call; 106, block; 107, identifier:searchels; 108, attribute; 109, argument_list; 110, call; 111, integer:1; 112, break_statement; 113, identifier:range; 114, argument_list; 115, if_statement; 116, if_statement; 117, identifier:searchels; 118, identifier:pop; 119, integer:0; 120, identifier:len; 121, argument_list; 122, call; 123, identifier:found; 124, block; 125, comparison_operator:s+l <= len(searchels); 126, block; 127, identifier:searchels; 128, identifier:len; 129, argument_list; 130, break_statement; 131, binary_operator:s+l; 132, call; 133, expression_statement; 134, expression_statement; 135, for_statement; 136, comment:# Searcs for the text in the whole txtsearch; 137, expression_statement; 138, if_statement; 139, identifier:searchels; 140, identifier:s; 141, identifier:l; 142, identifier:len; 143, argument_list; 144, assignment; 145, assignment; 146, identifier:k; 147, identifier:e; 148, block; 149, assignment; 150, identifier:match; 151, block; 152, identifier:searchels; 153, identifier:e; 154, call; 155, identifier:txtsearch; 156, string; 157, expression_statement; 158, identifier:match; 159, call; 160, expression_statement; 161, expression_statement; 162, identifier:range; 163, argument_list; 164, augmented_assignment; 165, attribute; 166, argument_list; 167, call; 168, assignment; 169, identifier:s; 170, binary_operator:s+l; 171, identifier:txtsearch; 172, attribute; 173, identifier:searchre; 174, identifier:search; 175, identifier:txtsearch; 176, attribute; 177, argument_list; 178, identifier:found; 179, True; 180, identifier:s; 181, identifier:l; 182, subscript; 183, identifier:text; 184, identifier:matches; 185, identifier:append; 186, call; 187, identifier:searchels; 188, identifier:k; 189, attribute; 190, argument_list; 191, identifier:match; 192, identifier:group
code: def AdvSearch(document, search, bs=3):
      '''Return set of all regex matches
  
      This is an advanced version of python-docx.search() that takes into
      account blocks of <bs> elements at a time.
  
      What it does:
      It searches the entire document body for text blocks.
      Since the text to search could be spawned across multiple text blocks,
      we need to adopt some sort of algorithm to handle this situation.
      The smaller matching group of blocks (up to bs) is then adopted.
      If the matching group has more than one block, blocks other than first
      are cleared and all the replacement text is put on first block.
  
      Examples:
      original text blocks : [ 'Hel', 'lo,', ' world!' ]
      search : 'Hello,'
      output blocks : [ 'Hello,' ]
  
      original text blocks : [ 'Hel', 'lo', ' __', 'name', '__!' ]
      search : '(__[a-z]+__)'
      output blocks : [ '__name__' ]
  
      @param instance  document: The original document
      @param str       search: The text to search for (regexp)
                            append, or a list of etree elements
      @param int       bs: See above
  
      @return set      All occurences of search string
  
      '''
  
      # Compile the search regexp
      searchre = re.compile(search)
  
      matches = []
  
      # Will match against searchels. Searchels is a list that contains last
      # n text elements found in the document. 1 < n < bs
      searchels = []
  
      for element in document.iter():
          if element.tag == '{%s}t' % nsprefixes['w']:  # t (text) elements
              if element.text:
                  # Add this element to searchels
                  searchels.append(element)
                  if len(searchels) > bs:
                      # Is searchels is too long, remove first elements
                      searchels.pop(0)
  
                  # Search all combinations, of searchels, starting from
                  # smaller up to bigger ones
                  # l = search lenght
                  # s = search start
                  # e = element IDs to merge
                  found = False
                  for l in range(1, len(searchels)+1):
                      if found:
                          break
                      for s in range(len(searchels)):
                          if found:
                              break
                          if s+l <= len(searchels):
                              e = range(s, s+l)
                              txtsearch = ''
                              for k in e:
                                  txtsearch += searchels[k].text
  
                              # Searcs for the text in the whole txtsearch
                              match = searchre.search(txtsearch)
                              if match:
                                  matches.append(match.group())
                                  found = True
      return set(matches)