Fixed #28135 -- Made simplify_regex() handle non-capturing groups.
This commit is contained in:
parent
fdfa97fb16
commit
0a17666045
|
@ -137,9 +137,10 @@ if docutils_is_available:
|
||||||
for name, urlbase in ROLES.items():
|
for name, urlbase in ROLES.items():
|
||||||
create_reference_role(name, urlbase)
|
create_reference_role(name, urlbase)
|
||||||
|
|
||||||
# Match the beginning of a named or unnamed group.
|
# Match the beginning of a named, unnamed, or non-capturing groups.
|
||||||
named_group_matcher = _lazy_re_compile(r'\(\?P(<\w+>)')
|
named_group_matcher = _lazy_re_compile(r'\(\?P(<\w+>)')
|
||||||
unnamed_group_matcher = _lazy_re_compile(r'\(')
|
unnamed_group_matcher = _lazy_re_compile(r'\(')
|
||||||
|
non_capturing_group_matcher = _lazy_re_compile(r'\(\?\:')
|
||||||
|
|
||||||
|
|
||||||
def replace_metacharacters(pattern):
|
def replace_metacharacters(pattern):
|
||||||
|
@ -210,3 +211,18 @@ def replace_unnamed_groups(pattern):
|
||||||
final_pattern += pattern[:start] + '<var>'
|
final_pattern += pattern[:start] + '<var>'
|
||||||
prev_end = end
|
prev_end = end
|
||||||
return final_pattern + pattern[prev_end:]
|
return final_pattern + pattern[prev_end:]
|
||||||
|
|
||||||
|
|
||||||
|
def remove_non_capturing_groups(pattern):
|
||||||
|
r"""
|
||||||
|
Find non-capturing groups in the given `pattern` and remove them, e.g.
|
||||||
|
1. (?P<a>\w+)/b/(?:\w+)c(?:\w+) => (?P<a>\\w+)/b/c
|
||||||
|
2. ^(?:\w+(?:\w+))a => ^a
|
||||||
|
3. ^a(?:\w+)/b(?:\w+) => ^a/b
|
||||||
|
"""
|
||||||
|
group_start_end_indices = _find_groups(pattern, non_capturing_group_matcher)
|
||||||
|
final_pattern, prev_end = '', None
|
||||||
|
for start, end, _ in group_start_end_indices:
|
||||||
|
final_pattern += pattern[prev_end:start]
|
||||||
|
prev_end = end
|
||||||
|
return final_pattern + pattern[prev_end:]
|
||||||
|
|
|
@ -8,7 +8,8 @@ from django.contrib import admin
|
||||||
from django.contrib.admin.views.decorators import staff_member_required
|
from django.contrib.admin.views.decorators import staff_member_required
|
||||||
from django.contrib.admindocs import utils
|
from django.contrib.admindocs import utils
|
||||||
from django.contrib.admindocs.utils import (
|
from django.contrib.admindocs.utils import (
|
||||||
replace_metacharacters, replace_named_groups, replace_unnamed_groups,
|
remove_non_capturing_groups, replace_metacharacters, replace_named_groups,
|
||||||
|
replace_unnamed_groups,
|
||||||
)
|
)
|
||||||
from django.core.exceptions import ImproperlyConfigured, ViewDoesNotExist
|
from django.core.exceptions import ImproperlyConfigured, ViewDoesNotExist
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
@ -410,6 +411,7 @@ def simplify_regex(pattern):
|
||||||
example, turn "^(?P<sport_slug>\w+)/athletes/(?P<athlete_slug>\w+)/$"
|
example, turn "^(?P<sport_slug>\w+)/athletes/(?P<athlete_slug>\w+)/$"
|
||||||
into "/<sport_slug>/athletes/<athlete_slug>/".
|
into "/<sport_slug>/athletes/<athlete_slug>/".
|
||||||
"""
|
"""
|
||||||
|
pattern = remove_non_capturing_groups(pattern)
|
||||||
pattern = replace_named_groups(pattern)
|
pattern = replace_named_groups(pattern)
|
||||||
pattern = replace_unnamed_groups(pattern)
|
pattern = replace_unnamed_groups(pattern)
|
||||||
pattern = replace_metacharacters(pattern)
|
pattern = replace_metacharacters(pattern)
|
||||||
|
|
|
@ -397,6 +397,13 @@ class AdminDocViewFunctionsTests(SimpleTestCase):
|
||||||
(r'^(?P<a>(x|y))/b/(?P<c>\w+)', '/<a>/b/<c>'),
|
(r'^(?P<a>(x|y))/b/(?P<c>\w+)', '/<a>/b/<c>'),
|
||||||
(r'^(?P<a>(x|y))/b/(?P<c>\w+)ab', '/<a>/b/<c>ab'),
|
(r'^(?P<a>(x|y))/b/(?P<c>\w+)ab', '/<a>/b/<c>ab'),
|
||||||
(r'^(?P<a>(x|y)(\(|\)))/b/(?P<c>\w+)ab', '/<a>/b/<c>ab'),
|
(r'^(?P<a>(x|y)(\(|\)))/b/(?P<c>\w+)ab', '/<a>/b/<c>ab'),
|
||||||
|
# Non-capturing groups.
|
||||||
|
(r'^a(?:\w+)b', '/ab'),
|
||||||
|
(r'^a(?:(x|y))', '/a'),
|
||||||
|
(r'^(?:\w+(?:\w+))a', '/a'),
|
||||||
|
(r'^a(?:\w+)/b(?:\w+)', '/a/b'),
|
||||||
|
(r'(?P<a>\w+)/b/(?:\w+)c(?:\w+)', '/<a>/b/c'),
|
||||||
|
(r'(?P<a>\w+)/b/(\w+)/(?:\w+)c(?:\w+)', '/<a>/b/<var>/c'),
|
||||||
# Single and repeated metacharacters.
|
# Single and repeated metacharacters.
|
||||||
(r'^a', '/a'),
|
(r'^a', '/a'),
|
||||||
(r'^^a', '/a'),
|
(r'^^a', '/a'),
|
||||||
|
|
Loading…
Reference in New Issue