[Tutor] ratios with regular expressions, split?

Tim Peters tutor@python.org
Thu, 12 Jul 2001 23:51:46 -0400


[kevin parks]
> One of the things that i am trying to do is calcualte,
> manuipulate, and plain old fondle ratios. I need to be able to
> input a series of ratios such as:
>
>     6/5, 10/9, 9/8, 6/5, 10/9
>
> and then split them up in to numerator/denominator pairs for each
> one, so that
>
> 6/5 would be dumped in to 2 variables, say num1, denom1 and
> 10/9 would be assigned to say num2, denom2
>
> etc...
>
>
> Additionally the ratios might also be input as 7:6 or 7/6 and
> some have a different number of digits, like 3/2, 81/80 and
> 127/128, etc. Also there is no way to tell in advance if there
> will be a series of 3 ratios, 4 ratios, or 53 ratios. What is the
> best way to do this? with regex or split?

Don't try to do too much at once.  Start simple!  For example, let's build a
regexp to match a single ratio in isolation, possibly surrounded by
whitespace:

import re

_ratio_re = re.compile("""
    \s*                     # skip leading whitespace
    (\d+)                   # group 1 has one or more digits
    [:/]                    # separated by colon or slash
    (\d+)                   # group 2 has one or more digits
    \s*                     # skip trailing whitespace
    $                       # and insist we're at the end of the string
""", re.VERBOSE).match

# Now we can build a parsing function.

def parse_ratio(s):
    """Parse string s as a ratio.  Return (numerator, denominator)."""
    m = _ratio_re(s)
    if m:
        n, d = m.groups()
        return int(n), int(d)
    else:
        raise SyntaxError("%r doesn't look like a ratio!" % s)

Then get into an interactive shell and *try* it:

>>> parse_ratio("1/2")
(1, 2)
>>> parse_ratio("  23423:234   ")
(23423, 234)
>>> parse_ratio("-1/2")
Traceback (most recent call last):
  File "<pyshell#4>", line 1, in ?
    parse_ratio("-1/2")
  File "C:/Python21/ratparse.py", line 21, in parse_ratio
    raise SyntaxError("%r doesn't look like a ratio!" % s)
SyntaxError: '-1/2' doesn't look like a ratio!
>>>

Play around; see whether or not you're happy with it.  If you're not, change
the regexp until you are.

Soon you'll have a solid building block for doing fancier things.  For
example,

>>> for chunk in "6/5, 10/9, 9/8, 6/5, 10/9".split(','):
	print parse_ratio(chunk)

(6, 5)
(10, 9)
(9, 8)
(6, 5)
(10, 9)
>>>

Regular expressions are very good for parsing simple and, umm, "regular"
expressions.  They'll drive you nuts if you try to do too much with them,
though.  I'd leave splitting on whitespace, or by commas (etc), to the
string.split() function, which is simpler, quicker and easier to understand
for that purpose.

> ...
> ps. be nice to me it is my birthday (34! Ughh!) and i am all
> alone (except for my python book and the interpreter and maybe
> some kimchee soup a bit later)

You mean it's possible to spend a birthday *not* playing with Python?!  Hmm.
I doubt I have many birthdays remaining, but I'll give that a try just once
<wink>.

Happy birthday, Kevin!

and-wishing-you-34-more-for-starters-ly y'rs  - tim