diff options
| author | Jon Dufresne <jon.dufresne@gmail.com> | 2016-02-11 20:37:34 -0800 |
|---|---|---|
| committer | Tim Graham <timograham@gmail.com> | 2016-02-15 09:10:15 -0500 |
| commit | dec334cb66b3ee59cb82e1bb99a584aa0b9fbbd5 (patch) | |
| tree | 772e42ce55dbb410b6426e098f5a83d54de678d9 /django/utils/html.py | |
| parent | fcd08c175787e909b3eb98f756317a07741c48dd (diff) | |
Fixed #26193 -- Made urlize() trim multiple trailing punctuation.
Diffstat (limited to 'django/utils/html.py')
| -rw-r--r-- | django/utils/html.py | 53 |
1 files changed, 40 insertions, 13 deletions
diff --git a/django/utils/html.py b/django/utils/html.py index 89d6a00eb2..de515ef8e9 100644 --- a/django/utils/html.py +++ b/django/utils/html.py @@ -17,7 +17,12 @@ from django.utils.text import normalize_newlines from .html_parser import HTMLParseError, HTMLParser # Configuration for urlize() function. -TRAILING_PUNCTUATION = ['.', ',', ':', ';', '.)', '"', '\'', '!'] +TRAILING_PUNCTUATION_RE = re.compile( + '^' # Beginning of word + '(.*?)' # The URL in word + '([.,:;!]+)' # Allowed non-wrapping, trailing punctuation + '$' # End of word +) WRAPPING_PUNCTUATION = [('(', ')'), ('<', '>'), ('[', ']'), ('<', '>'), ('"', '"'), ('\'', '\'')] # List of possible strings used for bullets in bulleted lists. @@ -268,24 +273,46 @@ def urlize(text, trim_url_limit=None, nofollow=False, autoescape=False): trail = '' return text, unescaped, trail - words = word_split_re.split(force_text(text)) - for i, word in enumerate(words): - if '.' in word or '@' in word or ':' in word: - # Deal with punctuation. - lead, middle, trail = '', word, '' - for punctuation in TRAILING_PUNCTUATION: - if middle.endswith(punctuation): - middle = middle[:-len(punctuation)] - trail = punctuation + trail + def trim_punctuation(lead, middle, trail): + """ + Trim trailing and wrapping punctuation from `middle`. Return the items + of the new state. + """ + # Continue trimming until middle remains unchanged. + trimmed_something = True + while trimmed_something: + trimmed_something = False + + # Trim trailing punctuation. + match = TRAILING_PUNCTUATION_RE.match(middle) + if match: + middle = match.group(1) + trail = match.group(2) + trail + trimmed_something = True + + # Trim wrapping punctuation. for opening, closing in WRAPPING_PUNCTUATION: if middle.startswith(opening): middle = middle[len(opening):] - lead = lead + opening + lead += opening + trimmed_something = True # Keep parentheses at the end only if they're balanced. - if (middle.endswith(closing) - and middle.count(closing) == middle.count(opening) + 1): + if (middle.endswith(closing) and + middle.count(closing) == middle.count(opening) + 1): middle = middle[:-len(closing)] trail = closing + trail + trimmed_something = True + return lead, middle, trail + + words = word_split_re.split(force_text(text)) + for i, word in enumerate(words): + if '.' in word or '@' in word or ':' in word: + # lead: Current punctuation trimmed from the beginning of the word. + # middle: Current state of the word. + # trail: Current punctuation trimmed from the end of the word. + lead, middle, trail = '', word, '' + # Deal with punctuation. + lead, middle, trail = trim_punctuation(lead, middle, trail) # Make URL we want to point to. url = None |
