@@ -53,20 +53,6 @@ def _hash_algorithm(numerator, denominator):
5353 result = hash_ if numerator >= 0 else - hash_
5454 return - 2 if result == - 1 else result
5555
56- _RATIONAL_FORMAT = re .compile (r"""
57- \A\s* # optional whitespace at the start,
58- (?P<sign>[-+]?) # an optional sign, then
59- (?=\d|\.\d) # lookahead for digit or .digit
60- (?P<num>\d*|\d+(_\d+)*) # numerator (possibly empty)
61- (?: # followed by
62- (?:\s*/\s*(?P<denom>\d+(_\d+)*))? # an optional denominator
63- | # or
64- (?:\.(?P<decimal>\d*|\d+(_\d+)*))? # an optional fractional part
65- (?:E(?P<exp>[-+]?\d+(_\d+)*))? # and optional exponent
66- )
67- \s*\z # and optional whitespace to finish
68- """ , re .VERBOSE | re .IGNORECASE )
69-
7056
7157# Helpers for formatting
7258
@@ -238,11 +224,6 @@ def __new__(cls, numerator=0, denominator=None):
238224 self ._denominator = 1
239225 return self
240226
241- elif isinstance (numerator , numbers .Rational ):
242- self ._numerator = numerator .numerator
243- self ._denominator = numerator .denominator
244- return self
245-
246227 elif (isinstance (numerator , float ) or
247228 (not isinstance (numerator , type ) and
248229 hasattr (numerator , 'as_integer_ratio' ))):
@@ -252,31 +233,52 @@ def __new__(cls, numerator=0, denominator=None):
252233
253234 elif isinstance (numerator , str ):
254235 # Handle construction from strings.
255- m = _RATIONAL_FORMAT .match (numerator )
256- if m is None :
257- raise ValueError ('Invalid literal for Fraction: %r' %
258- numerator )
259- numerator = int (m .group ('num' ) or '0' )
260- denom = m .group ('denom' )
261- if denom :
262- denominator = int (denom )
263- else :
264- denominator = 1
265- decimal = m .group ('decimal' )
266- if decimal :
267- decimal = decimal .replace ('_' , '' )
268- scale = 10 ** len (decimal )
269- numerator = numerator * scale + int (decimal )
270- denominator *= scale
271- exp = m .group ('exp' )
272- if exp :
273- exp = int (exp )
274- if exp >= 0 :
275- numerator *= 10 ** exp
236+ fraction_literal = numerator
237+ num , _ , denom = fraction_literal .partition ('/' )
238+ try :
239+ num = num .strip ()
240+ denom = denom .strip ()
241+ if num and denom and denom [0 ].isdigit ():
242+ denominator = int (denom )
243+ numerator = int (num )
244+ elif num and not _ :
245+ denominator = 1
246+ num , _ , exp = num .replace ('E' , 'e' ).partition ('e' )
247+ if _ and not exp :
248+ raise ValueError
249+ num , _ , decimal = num .partition ('.' )
250+ if decimal :
251+ if num and num [0 ] in ('+' , '-' ):
252+ sign = num [0 ] == '-'
253+ num = num [1 :]
254+ else :
255+ sign = 0
256+ numerator = int (num or '0' )
257+ decimal_len = len (decimal .replace ('_' , '' ))
258+ decimal = int (decimal )
259+ scale = 10 ** decimal_len
260+ numerator = numerator * scale + decimal
261+ denominator *= scale
262+ if sign :
263+ numerator = - numerator
276264 else :
277- denominator *= 10 ** - exp
278- if m .group ('sign' ) == '-' :
279- numerator = - numerator
265+ numerator = int (num )
266+ if exp :
267+ exp = int (exp )
268+ if exp >= 0 :
269+ numerator *= 10 ** exp
270+ else :
271+ denominator *= 10 ** - exp
272+ else :
273+ raise ValueError
274+ except ValueError :
275+ raise ValueError ('Invalid literal for Fraction: %r' %
276+ fraction_literal )
277+
278+ elif isinstance (numerator , numbers .Rational ):
279+ self ._numerator = numerator .numerator
280+ self ._denominator = numerator .denominator
281+ return self
280282
281283 else :
282284 raise TypeError ("argument should be a string or a Rational "
0 commit comments