Index: django/core/urlresolvers.py
===================================================================
--- django/core/urlresolvers.py	(revision 3954)
+++ django/core/urlresolvers.py	(working copy)
@@ -11,6 +11,13 @@
 from django.core.exceptions import ImproperlyConfigured, ViewDoesNotExist
 import re
 
+# Set up these regular expressions outside the function so they only have to
+# be compiled once.
+re_parenthesis = re.compile(r'(?<!\\)\((.*)(?<!\\)\)')  # Slashes handle the rare possibility of escaped brackets.
+re_named_group = re.compile(r'\?P<(\w+)>(.*)$')
+re_unused = re.compile(r'(?<!\\)\$|[?*+^]')
+re_special = re.compile(r'\\[.+*()$]')  # Characters from the IETF URL standard, RFC 1738.
+
 class Resolver404(Http404):
     pass
 
@@ -39,38 +46,64 @@
 
     Raises NoReverseMatch if the args/kwargs aren't valid for the regex.
     """
-    # TODO: Handle nested parenthesis in the following regex.
-    result = re.sub(r'\(([^)]+)\)', MatchChecker(args, kwargs), regex.pattern)
-    return result.replace('^', '').replace('$', '')
+    # Recursion is not necessary because the outermost matched parenthesis
+    # will be replaced with the given argument.
+    use_named_groups = bool(re_named_group.search(regex.pattern))
+    match_checker = MatchChecker(args, kwargs, use_named_groups)
+    result = re_parenthesis.sub(match_checker, regex.pattern)
+    # Strip unused regular expression syntax.
+    result = re_unused.sub('', result)
+    # Unescape special characters which could possibly be used in a URL.
+    result = re_special.sub('', result)
+    return result
 
 class MatchChecker(object):
     "Class used in reverse RegexURLPattern lookup."
-    def __init__(self, args, kwargs):
+    def __init__(self, args, kwargs, use_named_groups):
         self.args, self.kwargs = args, kwargs
         self.current_arg = 0
+        self.use_named_groups = use_named_groups
 
     def __call__(self, match_obj):
         # match_obj.group(1) is the contents of the parenthesis.
         # First we need to figure out whether it's a named or unnamed group.
         #
         grouped = match_obj.group(1)
-        m = re.search(r'^\?P<(\w+)>(.*?)$', grouped)
-        if m: # If this was a named group...
-            # m.group(1) is the name of the group
-            # m.group(2) is the regex.
-            try:
-                value = self.kwargs[m.group(1)]
-            except KeyError:
-                # It was a named group, but the arg was passed in as a
-                # positional arg or not at all.
+
+        # Handle regular expression extension notation.
+        if grouped.startswith('?'):
+            grouped = grouped[1:]
+            if grouped.startswith(':'):
+                # Parse the contents of this non-grouping parenthesis.
+                value = re_parenthesis.sub(self, grouped[1:])
+                value = str(value) # TODO: Unicode?
+                return handle_pipe(value)
+            elif grouped.startswith('P'): 
+                # This is a named group.
+                pass
+            else:
+                # Ignore the all other types of extension notation.
+                return ''
+        
+        # If there is a named group in this regex, only parse named groups
+        # ignoring non-named arguments.
+        if self.use_named_groups:
+            if m: # If this was a named group...
+                # m.group(1) is the name of the group
+                # m.group(2) is the regex.
                 try:
-                    value = self.args[self.current_arg]
-                    self.current_arg += 1
-                except IndexError:
-                    # The arg wasn't passed in.
-                    raise NoReverseMatch('Not enough positional arguments passed in')
-            test_regex = m.group(2)
-        else: # Otherwise, this was a positional (unnamed) group.
+                    value = self.kwargs[m.group(1)]
+                except KeyError:
+                    # It was a named group, but the arg was passed in as a
+                    # positional arg or not at all.
+                    try:
+                        value = self.args[self.current_arg]
+                        self.current_arg += 1
+                    except IndexError:
+                        # The arg wasn't passed in.
+                        raise NoReverseMatch('Not enough positional arguments passed in')
+                test_regex = m.group(2)
+        else:
             try:
                 value = self.args[self.current_arg]
                 self.current_arg += 1
@@ -82,8 +115,18 @@
         # to string needs to match.
         if not re.match(test_regex + '$', str(value)): # TODO: Unicode?
             raise NoReverseMatch("Value %r didn't match regular expression %r" % (value, test_regex))
-        return str(value) # TODO: Unicode?
+        value = str(value) # TODO: Unicode?
+        return handle_pipe(value)
 
+def handle_pipe(value):
+    # Check for pipes (used in regular expressions for alternate matches).
+    # Since the matched expression can not be determined, the first one will
+    # be always used.
+    pipe = value.find('|')
+    if pipe != -1:
+        value = value[:pipe]
+    return value
+
 class RegexURLPattern(object):
     def __init__(self, regex, callback, default_args=None):
         # regex is a string representing a regular expression.
