~ubuntu-branches/ubuntu/quantal/python-django/quantal-security

« back to all changes in this revision

Viewing changes to django/utils/text.py

  • Committer: Bazaar Package Importer
  • Author(s): Chris Lamb
  • Date: 2010-05-21 07:52:55 UTC
  • mfrom: (1.3.6 upstream)
  • mto: This revision was merged to the branch mainline in revision 28.
  • Revision ID: james.westby@ubuntu.com-20100521075255-ii78v1dyfmyu3uzx
Tags: upstream-1.2
ImportĀ upstreamĀ versionĀ 1.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
import re
2
 
from django.conf import settings
3
2
from django.utils.encoding import force_unicode
4
3
from django.utils.functional import allow_lazy
5
4
from django.utils.translation import ugettext_lazy
37
36
    return u''.join(_generator())
38
37
wrap = allow_lazy(wrap, unicode)
39
38
 
40
 
def truncate_words(s, num):
41
 
    "Truncates a string after a certain number of words."
 
39
def truncate_words(s, num, end_text='...'):
 
40
    """Truncates a string after a certain number of words. Takes an optional
 
41
    argument of what should be used to notify that the string has been
 
42
    truncated, defaults to ellipsis (...)"""
42
43
    s = force_unicode(s)
43
44
    length = int(num)
44
45
    words = s.split()
45
46
    if len(words) > length:
46
47
        words = words[:length]
47
 
        if not words[-1].endswith('...'):
48
 
            words.append('...')
 
48
        if not words[-1].endswith(end_text):
 
49
            words.append(end_text)
49
50
    return u' '.join(words)
50
51
truncate_words = allow_lazy(truncate_words, unicode)
51
52
 
52
 
def truncate_html_words(s, num):
53
 
    """
54
 
    Truncates html to a certain number of words (not counting tags and
 
53
def truncate_html_words(s, num, end_text='...'):
 
54
    """Truncates html to a certain number of words (not counting tags and
55
55
    comments). Closes opened tags if they were correctly closed in the given
56
 
    html.
57
 
    """
 
56
    html. Takes an optional argument of what should be used to notify that the
 
57
    string has been truncated, defaults to ellipsis (...)."""
58
58
    s = force_unicode(s)
59
59
    length = int(num)
60
60
    if length <= 0:
65
65
    re_tag = re.compile(r'<(/)?([^ ]+?)(?: (/)| .*?)?>')
66
66
    # Count non-HTML words and keep note of open tags
67
67
    pos = 0
68
 
    ellipsis_pos = 0
 
68
    end_text_pos = 0
69
69
    words = 0
70
70
    open_tags = []
71
71
    while words <= length:
78
78
            # It's an actual non-HTML word
79
79
            words += 1
80
80
            if words == length:
81
 
                ellipsis_pos = pos
 
81
                end_text_pos = pos
82
82
            continue
83
83
        # Check for tag
84
84
        tag = re_tag.match(m.group(0))
85
 
        if not tag or ellipsis_pos:
 
85
        if not tag or end_text_pos:
86
86
            # Don't worry about non tags or tags after our truncate point
87
87
            continue
88
88
        closing_tag, tagname, self_closing = tag.groups()
104
104
    if words <= length:
105
105
        # Don't try to close tags if we don't need to truncate
106
106
        return s
107
 
    out = s[:ellipsis_pos] + ' ...'
 
107
    out = s[:end_text_pos]
 
108
    if end_text:
 
109
        out += ' ' + end_text
108
110
    # Close any tags still open
109
111
    for tag in open_tags:
110
112
        out += '</%s>' % tag
157
159
 
158
160
def phone2numeric(phone):
159
161
    "Converts a phone number with letters into its numeric equivalent."
160
 
    letters = re.compile(r'[A-PR-Y]', re.I)
161
 
    char2number = lambda m: {'a': '2', 'c': '2', 'b': '2', 'e': '3',
162
 
         'd': '3', 'g': '4', 'f': '3', 'i': '4', 'h': '4', 'k': '5',
163
 
         'j': '5', 'm': '6', 'l': '5', 'o': '6', 'n': '6', 'p': '7',
164
 
         's': '7', 'r': '7', 'u': '8', 't': '8', 'w': '9', 'v': '8',
165
 
         'y': '9', 'x': '9'}.get(m.group(0).lower())
 
162
    letters = re.compile(r'[A-Z]', re.I)
 
163
    char2number = lambda m: {'a': '2', 'b': '2', 'c': '2', 'd': '3', 'e': '3',
 
164
         'f': '3', 'g': '4', 'h': '4', 'i': '4', 'j': '5', 'k': '5', 'l': '5',
 
165
         'm': '6', 'n': '6', 'o': '6', 'p': '7', 'q': '7', 'r': '7', 's': '7',
 
166
         't': '8', 'u': '8', 'v': '8', 'w': '9', 'x': '9', 'y': '9', 'z': '9',
 
167
        }.get(m.group(0).lower())
166
168
    return letters.sub(char2number, phone)
167
169
phone2numeric = allow_lazy(phone2numeric)
168
170
 
186
188
    if type(s) == str:
187
189
        s = s.decode('utf-8')
188
190
    elif type(s) != unicode:
189
 
        raise TypeError, s
 
191
        raise TypeError(s)
190
192
    s = s.replace('\\', '\\\\')
191
193
    s = s.replace('\r', '\\r')
192
194
    s = s.replace('\n', '\\n')
200
202
# Expression to match some_token and some_token="with spaces" (and similarly
201
203
# for single-quoted strings).
202
204
smart_split_re = re.compile(r"""
203
 
    ([^\s"]*"(?:[^"\\]*(?:\\.[^"\\]*)*)"\S*|
204
 
     [^\s']*'(?:[^'\\]*(?:\\.[^'\\]*)*)'\S*|
205
 
     \S+)""", re.VERBOSE)
 
205
    ((?:
 
206
        [^\s'"]*
 
207
        (?:
 
208
            (?:"(?:[^"\\]|\\.)*" | '(?:[^'\\]|\\.)*')
 
209
            [^\s'"]*
 
210
        )+
 
211
    ) | \S+)
 
212
""", re.VERBOSE)
206
213
 
207
214
def smart_split(text):
208
215
    r"""