Home > Software design >  RegEx length range not working for Django/Python? (re.error: multiple repeat at position)
RegEx length range not working for Django/Python? (re.error: multiple repeat at position)

Time:10-27

I'm trying to add a custom Validator with a regex for username input.

The username should contain only a-z, A-Z, 0-9, and _ and be between 3 and 20 characters.

class Validator(validators.RegexValidator):
    regex = r"^[A-Za-z0-9_]{3,20} \Z"
    flags = re.ASCII

RegEx works fine when there's no character range i.e. r"^[A-Za-z0-9_] \Z"

And I think {3,20} is the correct way of specifying the length... so I'm not sure why the regex isn't working.

I get this error re.error: multiple repeat at position 19 regardless of the string that I'm trying to validate.

Full traceback:

backend-web-1  | Traceback (most recent call last):
backend-web-1  |   File "/usr/local/lib/python3.10/site-packages/django/core/handlers/exception.py", line 47, in inner
backend-web-1  |     response = get_response(request)
backend-web-1  |   File "/usr/local/lib/python3.10/site-packages/django/core/handlers/base.py", line 181, in _get_response
backend-web-1  |     response = wrapped_callback(request, *callback_args, **callback_kwargs)
backend-web-1  |   File "/usr/local/lib/python3.10/site-packages/django/views/decorators/csrf.py", line 54, in wrapped_view
backend-web-1  |     return view_func(*args, **kwargs)
backend-web-1  |   File "/usr/local/lib/python3.10/site-packages/django/views/generic/base.py", line 70, in view
backend-web-1  |     return self.dispatch(request, *args, **kwargs)
backend-web-1  |   File "/usr/local/lib/python3.10/site-packages/django/utils/decorators.py", line 43, in _wrapper
backend-web-1  |     return bound_method(*args, **kwargs)
backend-web-1  |   File "/usr/local/lib/python3.10/site-packages/django/views/decorators/debug.py", line 89, in sensitive_post_parameters_wrapper
backend-web-1  |     return view(request, *args, **kwargs)
backend-web-1  |   File "/usr/local/lib/python3.10/site-packages/dj_rest_auth/registration/views.py", line 47, in dispatch
backend-web-1  |     return super().dispatch(*args, **kwargs)
backend-web-1  |   File "/usr/local/lib/python3.10/site-packages/rest_framework/views.py", line 509, in dispatch
backend-web-1  |     response = self.handle_exception(exc)
backend-web-1  |   File "/usr/local/lib/python3.10/site-packages/rest_framework/views.py", line 469, in handle_exception
backend-web-1  |     self.raise_uncaught_exception(exc)
backend-web-1  |   File "/usr/local/lib/python3.10/site-packages/rest_framework/views.py", line 480, in raise_uncaught_exception
backend-web-1  |     raise exc
backend-web-1  |   File "/usr/local/lib/python3.10/site-packages/rest_framework/views.py", line 506, in dispatch
backend-web-1  |     response = handler(request, *args, **kwargs)
backend-web-1  |   File "/usr/local/lib/python3.10/site-packages/rest_framework/generics.py", line 190, in post
backend-web-1  |     return self.create(request, *args, **kwargs)
backend-web-1  |   File "/usr/local/lib/python3.10/site-packages/dj_rest_auth/registration/views.py", line 66, in create
backend-web-1  |     serializer.is_valid(raise_exception=True)
backend-web-1  |   File "/usr/local/lib/python3.10/site-packages/rest_framework/serializers.py", line 220, in is_valid
backend-web-1  |     self._validated_data = self.run_validation(self.initial_data)
backend-web-1  |   File "/usr/local/lib/python3.10/site-packages/rest_framework/serializers.py", line 419, in run_validation
backend-web-1  |     value = self.to_internal_value(data)
backend-web-1  |   File "/usr/local/lib/python3.10/site-packages/rest_framework/serializers.py", line 478, in to_internal_value
backend-web-1  |     validated_value = validate_method(validated_value)
backend-web-1  |   File "/usr/local/lib/python3.10/site-packages/dj_rest_auth/registration/serializers.py", line 205, in validate_username
backend-web-1  |     username = get_adapter().clean_username(username)
backend-web-1  |   File "/usr/local/lib/python3.10/site-packages/allauth/account/adapter.py", line 255, in clean_username
backend-web-1  |     validator(username)
backend-web-1  |   File "/usr/local/lib/python3.10/site-packages/django/core/validators.py", line 48, in __call__
backend-web-1  |     regex_matches = self.regex.search(str(value))
backend-web-1  |   File "/usr/local/lib/python3.10/site-packages/django/utils/functional.py", line 246, in inner
backend-web-1  |     self._setup()
backend-web-1  |   File "/usr/local/lib/python3.10/site-packages/django/utils/functional.py", line 382, in _setup
backend-web-1  |     self._wrapped = self._setupfunc()
backend-web-1  |   File "/usr/local/lib/python3.10/site-packages/django/utils/regex_helper.py", line 345, in _compile
backend-web-1  |     return re.compile(regex, flags)
backend-web-1  |   File "/usr/local/lib/python3.10/re.py", line 251, in compile
backend-web-1  |     return _compile(pattern, flags)
backend-web-1  |   File "/usr/local/lib/python3.10/re.py", line 303, in _compile
backend-web-1  |     p = sre_compile.compile(pattern, flags)
backend-web-1  |   File "/usr/local/lib/python3.10/sre_compile.py", line 764, in compile
backend-web-1  |     p = sre_parse.parse(p, flags)
backend-web-1  |   File "/usr/local/lib/python3.10/sre_parse.py", line 948, in parse
backend-web-1  |     p = _parse_sub(source, state, flags & SRE_FLAG_VERBOSE, 0)
backend-web-1  |   File "/usr/local/lib/python3.10/sre_parse.py", line 443, in _parse_sub
backend-web-1  |     itemsappend(_parse(source, state, verbose, nested   1,
backend-web-1  |   File "/usr/local/lib/python3.10/sre_parse.py", line 671, in _parse
backend-web-1  |     raise source.error("multiple repeat",
backend-web-1  | re.error: multiple repeat at position 19

CodePudding user response:

This does not really have anything to do with Django. The pattern itself is illegal (at least in Python).

{3,20} already says "3 to 20 times". Having (which means "one or more times") immediately after it makes no sense.

The pattern you are looking for is r"^[A-Za-z0-9_]{3,20}\Z".

EDIT: Apparently {3,20} is legal in some regex engines (not Python's), but then means something else (ie not "one or more times of the last match"). See http://www.rexegg.com/regex-quantifiers.html#possessive (Thanks to @The fourth bird for the link)

  • Related