Ticket #4394: fraction3.diff

File fraction3.diff, 6.5 KB (added by max.rabkin@…, 12 years ago)

only uses unicode fractions which are supported by IE 5, and doesn't use sup and sub

  • django/contrib/humanize/templatetags/humanize.py

     
    6767        return value
    6868    return (_('one'), _('two'), _('three'), _('four'), _('five'), _('six'), _('seven'), _('eight'), _('nine'))[value-1]
    6969register.filter(apnumber)
     70
     71def _to_frac(x, maxdenom=10):
     72    """
     73    Convert x to a common fraction.
     74   
     75    Chooses the closest fraction to x with denominator <= maxdenom.
     76    If x is closest to an integer, return that integer; otherwise,
     77    return an (integer, numerator, denominator) tuple.
     78    """
     79   
     80    assert x >= 0, "_to_frac only works on positive numbers."
     81   
     82    intpart = int(x)
     83    x -= intpart
     84   
     85    bestfrac = 0,1
     86    mindiff = x
     87   
     88    for denom in range(1,maxdenom+1):
     89        # for each denominator, there are two numerators to consider:
     90        # the one below x and the one above x
     91        for num in (int(x*denom), int(x*denom+1)):
     92            diff = abs(float(num)/denom - x)
     93           
     94            # compare using '<' rather than '<=' to ensure that the
     95            # fraction with the smallest denominator is preferred
     96            if diff < mindiff:
     97                bestfrac = num, denom
     98                mindiff = diff
     99   
     100    if bestfrac[0] == 0:
     101        return intpart
     102    elif mindiff >= 1-x:
     103        return intpart+1
     104    else:
     105        return intpart, bestfrac[0], bestfrac[1]
     106
     107
     108_frac_entities = {(1,4): "&frac14;", (1,2): "&frac12;", (3,4): "&frac34;",
     109    (1, 3): "&#x2153;", (2, 3): "&#x2154;",
     110# browser support for fifths and sixths is incomplete, so we don't use them by default
     111#   (1, 5): "&#x2155;", (2, 5): "&#x2156;", (3, 5): "&#x2157;", (4, 5): "&#x2158;",
     112#   (1, 6): "&#x2159;", (5, 6): "&#x215A;",
     113    (1, 8): "&#x215B;", (3, 8): "&#x215C;", (5, 8): "&#x215D;", (7, 8): "&#x215E;"}
     114
     115def html_fraction (number, maxdenom=10, useUnicode=True):
     116    """
     117    Convert a float to a common fraction (or an integer if it is closer).
     118   
     119    If the output is a fraction, the fraction part is wrapped in a span
     120    with class "fraction" to enable styling of fractions.
     121   
     122    If useUnicode is true, unicode entities will be used where available.
     123    """
     124   
     125    number = float(number)
     126    frac = _to_frac(abs(number), maxdenom)
     127   
     128    if type(frac) == int:
     129        string = str(frac)
     130    else:
     131        intpart, numerator, denominator = frac
     132        if useUnicode and (numerator, denominator) in _frac_entities:
     133            fracpart = _frac_entities[(numerator, denominator)]
     134        else:
     135            fracpart = (('<span class="fraction">' +
     136                         '<span class="numerator">%i</span>&#x2044;' +
     137                         '<span class="denominator">%i</span></span>') %
     138                        (numerator,denominator))
     139        if intpart == 0:
     140            string = fracpart
     141        else:
     142            string = str(intpart) + fracpart
     143   
     144    if number < 0:
     145        return '-'+string
     146    else:
     147        return string
     148register.filter(html_fraction)
     149
     150def text_fraction (number, maxdenom=10):
     151    """Convert a float to a common fraction (or integer if it is closer)."""
     152   
     153    number = float(number)
     154    frac = _to_frac(abs(number), maxdenom)
     155   
     156    if type(frac) == int:
     157        string = str(frac)
     158    else:
     159        intpart, numerator, denominator = frac
     160        if intpart == 0:
     161            string = '%i/%i' % frac[1:]
     162        else:
     163            string = '%i %i/%i' % frac
     164   
     165    if number < 0:
     166        return '-'+string
     167    else:
     168        return string
     169register.filter(text_fraction)
  • tests/regressiontests/humanize/tests.py

     
    4848                       'seven', 'eight', 'nine', '10')
    4949
    5050        self.humanize_tester(test_list, result_list, 'apnumber')
     51   
     52    def test_html_fraction(self):
     53        test_list = ['0', '0.5', '1.667', '-0.25', '-1.75', '9.99', '-3.2857']
     54        result_list = ['0', '&frac12;', '1&#x2154;',
     55                       '-&frac14;', '-1&frac34;', '10',
     56'-3<span class="fraction"><span class="numerator">2</span>&#x2044;<span class="denominator">7</span></span>']
     57                       
     58        test_list = test_list + [float(num) for num in test_list]
     59        result_list *= 2
     60       
     61        self.humanize_tester(test_list, result_list, 'html_fraction')
     62   
     63    def test_text_fraction(self):
     64        test_list = ['0', '0.5', '1.667', '-0.25', '-1.75', '9.99']
     65        result_list = ['0', '1/2', '1 2/3', '-1/4', '-1 3/4', '10']
     66       
     67        test_list = test_list + [float(num) for num in test_list]
     68        result_list *= 2
     69       
     70        self.humanize_tester(test_list, result_list, 'text_fraction')
    5171
    5272if __name__ == '__main__':
    5373    unittest.main()
  • AUTHORS

     
    188188    plisk
    189189    Daniel Poelzleithner <http://poelzi.org/>
    190190    polpak@yahoo.com
     191    Max Rabkin <max.rabkin@gmail.com>
    191192    J. Rademaker
    192193    Michael Radziej <mir@noris.de>
    193194    Ramiro Morales <rm0@gmx.net>
  • docs/add_ons.txt

     
    135135
    136136You can pass in either an integer or a string representation of an integer.
    137137
     138text_fraction
     139-------------
     140
     141Converts a decimal fraction to a common fraction.
     142
     143Examples:
     144
     145    * ``0.5`` becomes ``'1/2'``
     146    * ``9.99`` becomes ``'10'``
     147    * ``-1.25`` becomes ``'-1 1/4'``
     148
     149You can pass in either an integer or a string representation of an integer.
     150
     151html_fraction
     152-------------
     153
     154Like text_fraction, but generates HTML so the fraction is rendered nicely.
     155If there is a (well-supported) Unicode character for the fraction it is used.
     156Otherwise the fractional part of the output is wrapped in
     157``<span class="fraction">`` tags, the top part is wrapped in
     158``<span class="numerator">`` and the bottom in ``<span class="denominator">``
     159tags. You'll need to add these classes to your CSS to make the fractions look
     160the way you want them.
     161
     162Example:
     163   
     164    * 3<span class="fraction"><span class="numerator">2</span>&#x2044;<span class="denominator>7</span></span>
     165
    138166flatpages
    139167=========
    140168
Back to Top