mirror of
				https://github.com/django/django.git
				synced 2025-10-31 09:41:08 +00:00 
			
		
		
		
	Refs #28135 -- Refactored out _find_groups()/_get_group_start_end() hooks in admindocs.
This commit is contained in:
		
				
					committed by
					
						 Mariusz Felisiak
						Mariusz Felisiak
					
				
			
			
				
	
			
			
			
						parent
						
							45a42aabfa
						
					
				
				
					commit
					827bc07047
				
			| @@ -151,23 +151,8 @@ def replace_metacharacters(pattern): | |||||||
|     ) |     ) | ||||||
|  |  | ||||||
|  |  | ||||||
| def replace_named_groups(pattern): | def _get_group_start_end(start, end, pattern): | ||||||
|     r""" |     # Handle nested parentheses, e.g. '^(?P<a>(x|y))/b' or '^b/((x|y)\w+)$'. | ||||||
|     Find named groups in `pattern` and replace them with the group name. E.g., |  | ||||||
|     1. ^(?P<a>\w+)/b/(\w+)$ ==> ^<a>/b/(\w+)$ |  | ||||||
|     2. ^(?P<a>\w+)/b/(?P<c>\w+)/$ ==> ^<a>/b/<c>/$ |  | ||||||
|     3. ^(?P<a>\w+)/b/(\w+) ==> ^<a>/b/(\w+) |  | ||||||
|     4. ^(?P<a>\w+)/b/(?P<c>\w+) ==> ^<a>/b/<c> |  | ||||||
|     """ |  | ||||||
|     named_group_indices = [ |  | ||||||
|         (m.start(0), m.end(0), m[1]) |  | ||||||
|         for m in named_group_matcher.finditer(pattern) |  | ||||||
|     ] |  | ||||||
|     # Tuples of (named capture group pattern, group name). |  | ||||||
|     group_pattern_and_name = [] |  | ||||||
|     # Loop over the groups and their start and end indices. |  | ||||||
|     for start, end, group_name in named_group_indices: |  | ||||||
|         # Handle nested parentheses, e.g. '^(?P<a>(x|y))/b'. |  | ||||||
|     unmatched_open_brackets, prev_char = 1, None |     unmatched_open_brackets, prev_char = 1, None | ||||||
|     for idx, val in enumerate(pattern[end:]): |     for idx, val in enumerate(pattern[end:]): | ||||||
|         # Check for unescaped `(` and `)`. They mark the start and end of a |         # Check for unescaped `(` and `)`. They mark the start and end of a | ||||||
| @@ -177,13 +162,34 @@ def replace_named_groups(pattern): | |||||||
|         elif val == ')' and prev_char != '\\': |         elif val == ')' and prev_char != '\\': | ||||||
|             unmatched_open_brackets -= 1 |             unmatched_open_brackets -= 1 | ||||||
|         prev_char = val |         prev_char = val | ||||||
|             # If brackets are balanced, the end of the string for the current |         # If brackets are balanced, the end of the string for the current named | ||||||
|             # named capture group pattern has been reached. |         # capture group pattern has been reached. | ||||||
|         if unmatched_open_brackets == 0: |         if unmatched_open_brackets == 0: | ||||||
|                 group_pattern_and_name.append((pattern[start:end + idx + 1], group_name)) |             return start, end + idx + 1 | ||||||
|                 break |  | ||||||
|  |  | ||||||
|     # Replace the string for named capture groups with their group names. |  | ||||||
|  | def _find_groups(pattern, group_matcher): | ||||||
|  |     prev_end = None | ||||||
|  |     for match in group_matcher.finditer(pattern): | ||||||
|  |         if indices := _get_group_start_end(match.start(0), match.end(0), pattern): | ||||||
|  |             start, end = indices | ||||||
|  |             if prev_end and start > prev_end or not prev_end: | ||||||
|  |                 yield start, end, match | ||||||
|  |             prev_end = end | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def replace_named_groups(pattern): | ||||||
|  |     r""" | ||||||
|  |     Find named groups in `pattern` and replace them with the group name. E.g., | ||||||
|  |     1. ^(?P<a>\w+)/b/(\w+)$ ==> ^<a>/b/(\w+)$ | ||||||
|  |     2. ^(?P<a>\w+)/b/(?P<c>\w+)/$ ==> ^<a>/b/<c>/$ | ||||||
|  |     3. ^(?P<a>\w+)/b/(\w+) ==> ^<a>/b/(\w+) | ||||||
|  |     4. ^(?P<a>\w+)/b/(?P<c>\w+) ==> ^<a>/b/<c> | ||||||
|  |     """ | ||||||
|  |     group_pattern_and_name = [ | ||||||
|  |         (pattern[start:end], match[1]) | ||||||
|  |         for start, end, match in _find_groups(pattern, named_group_matcher) | ||||||
|  |     ] | ||||||
|     for group_pattern, group_name in group_pattern_and_name: |     for group_pattern, group_name in group_pattern_and_name: | ||||||
|         pattern = pattern.replace(group_pattern, group_name) |         pattern = pattern.replace(group_pattern, group_name) | ||||||
|     return pattern |     return pattern | ||||||
| @@ -197,44 +203,10 @@ def replace_unnamed_groups(pattern): | |||||||
|     3. ^(?P<a>\w+)/b/(\w+) ==> ^(?P<a>\w+)/b/<var> |     3. ^(?P<a>\w+)/b/(\w+) ==> ^(?P<a>\w+)/b/<var> | ||||||
|     4. ^(?P<a>\w+)/b/((x|y)\w+) ==> ^(?P<a>\w+)/b/<var> |     4. ^(?P<a>\w+)/b/((x|y)\w+) ==> ^(?P<a>\w+)/b/<var> | ||||||
|     """ |     """ | ||||||
|     unnamed_group_indices = [m.start(0) for m in unnamed_group_matcher.finditer(pattern)] |     final_pattern, prev_end = '', None | ||||||
|     # Indices of the start of unnamed capture groups. |     for start, end, _ in _find_groups(pattern, unnamed_group_matcher): | ||||||
|     group_indices = [] |  | ||||||
|     # Loop over the start indices of the groups. |  | ||||||
|     for start in unnamed_group_indices: |  | ||||||
|         # Handle nested parentheses, e.g. '^b/((x|y)\w+)$'. |  | ||||||
|         unmatched_open_brackets, prev_char = 1, None |  | ||||||
|         for idx, val in enumerate(pattern[start + 1:]): |  | ||||||
|             # Check for unescaped `(` and `)`. They mark the start and end of |  | ||||||
|             # a nested group. |  | ||||||
|             if val == '(' and prev_char != '\\': |  | ||||||
|                 unmatched_open_brackets += 1 |  | ||||||
|             elif val == ')' and prev_char != '\\': |  | ||||||
|                 unmatched_open_brackets -= 1 |  | ||||||
|             prev_char = val |  | ||||||
|  |  | ||||||
|             if unmatched_open_brackets == 0: |  | ||||||
|                 group_indices.append((start, start + 2 + idx)) |  | ||||||
|                 break |  | ||||||
|     # Remove unnamed group matches inside other unnamed capture groups. |  | ||||||
|     group_start_end_indices = [] |  | ||||||
|     prev_end = None |  | ||||||
|     for start, end in group_indices: |  | ||||||
|         if prev_end and start > prev_end or not prev_end: |  | ||||||
|             group_start_end_indices.append((start, end)) |  | ||||||
|         prev_end = end |  | ||||||
|  |  | ||||||
|     if group_start_end_indices: |  | ||||||
|         # Replace unnamed groups with <var>. Handle the fact that replacing the |  | ||||||
|         # string between indices will change string length and thus indices |  | ||||||
|         # will point to the wrong substring if not corrected. |  | ||||||
|         final_pattern, prev_end = [], None |  | ||||||
|         for start, end in group_start_end_indices: |  | ||||||
|         if prev_end: |         if prev_end: | ||||||
|                 final_pattern.append(pattern[prev_end:start]) |             final_pattern += pattern[prev_end:start] | ||||||
|             final_pattern.append(pattern[:start] + '<var>') |         final_pattern += pattern[:start] + '<var>' | ||||||
|         prev_end = end |         prev_end = end | ||||||
|         final_pattern.append(pattern[prev_end:]) |     return final_pattern + pattern[prev_end:] | ||||||
|         return ''.join(final_pattern) |  | ||||||
|     else: |  | ||||||
|         return pattern |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user