import re def replace_groups(pattern, args=None, kwargs=None): """ This function takes a pattern with groups and replace them with the given args and/or kwargs. Example: IMPORTANT: this code is NOT to use replacing Django's reverse function. The example below is just to illustrate how it works. For a given pattern '/docs/(\d+)/rev/(\w+)/', args=(123,'abc') and kwargs={}, returns '/docs/123/rev/abc/'. For '/docs/(?P\d+)/rev/(?P\w+)/', args=() and kwargs={'rev':'abc', 'id':123} returns '/docs/123/rev/abc/' as well. For now, when both args and kwargs are given, raises a ValueError. """ if args and kwargs: raise ValueError("Informed both *args and **kwargs it's not supported.") exp_kwarg = re.compile('^\(\?P<(\w+)>(.+)\)$') # Used to check named arguments new = '' cur_group = '' group_count = 0 for ch in pattern: if ch == '(': group_count += 1 cur_group += ch elif ch == ')': group_count -= 1 cur_group += ch if not group_count: m_kwarg = exp_kwarg.match(cur_group) if m_kwarg: value = str(kwargs.pop(m_kwarg.group(1))) else: value = str(args[0]) args = args[1:] if re.match('^%s$'%cur_group, value): new += value cur_group = '' elif group_count: cur_group += ch else: new += ch return new